package com.shop2cn.iapi.sqoptrade.verify;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

import com.ymttest.business.service.shenqi.*;
import org.apache.commons.collections.CollectionUtils;

import com.shop2cn.iapi.points.resp.CalcOrderCreditResp;
import com.shop2cn.iapi.sqoptrade.parameter.enums.RiskControlStatusEnum;
import com.shop2cn.iapi.sqoptrade.parameter.enums.SqSellerRoleEnum;
import com.shop2cn.iapi.sqoptrade.parameter.model.placeorder.MainOrder;
import com.shop2cn.iapi.sqoptrade.parameter.model.placeorder.Order;
import com.shop2cn.iapi.sqoptrade.parameter.model.placeorder.OrderGroup;
import com.shop2cn.iapi.sqoptrade.parameter.model.placeorder.OrderItem;
import com.shop2cn.iapi.sqoptrade.parameter.req.CdfDeductCouponBeforePlaceReq;
import com.shop2cn.iapi.sqoptrade.parameter.req.PlaceOrderReq;
import com.shop2cn.iapi.sqoptrade.parameter.utill.Utils;
import com.shop2cn.iapi.sqoptrade.parameter.vo.BizVo;
import com.shop2cn.iapi.sqoptrade.parameter.vo.CouponVo;
import com.shop2cn.iapi.sqoptrade.parameter.vo.OrderGroupVo;
import com.shop2cn.iapi.sqoptrade.parameter.vo.OrderItemVo;
import com.shop2cn.iapi.sqoptrade.parameter.vo.OrderVo;
import com.shop2cn.iapi.sqoptrade.parameter.vo.OrderVoForCdfCoupon;
import com.shop2cn.iapi.sqoptrade.parameter.vo.PickInStoreVo;
import com.shop2cn.iapi.sqoptrade.parameter.vo.ProductVoForCdfCoupon;
import com.shop2cn.iapi.sqoptrade.parameter.vo.SellerPromotionVo;
import com.shop2cn.iapi.sqoptrade.parameter.vo.TravelerVo;
import com.shop2cn.iapi.sqoptrade.resp.CdfDeductCouponBeforePlaceResp;
import com.shop2cn.iapi.sqoptrade.resp.PlaceOrderResp;
import com.shop2cn.iapi.sqoptrade.resp.vo.CouponAmountVo;
import com.shop2cn.iapi.sqoptrade.service.PlaceOrderCall;
import com.ymatou.common.lang.CipherUtil;
import com.ymatou.tool.FormatUtil;
import com.ymt.core.tool.Logger;
import com.ymttest.business.service.shenqi.bean.PackageInfoByCatalogIdListResponse;
import com.ymttest.business.service.shenqi.bean.ShenqiUserSet;
import com.ymttest.business.service.shenqi.bean.SubCatalog;
import com.ymttest.database.model.DGUserInfo;
import com.ymttest.database.model.shenqi.SqliveOrderDetail;
import com.ymttest.database.sharding.db.ext.model.OrderDetailExtPo;
import com.ymttest.database.sharding.db.ext.model.OrderExtPo;
import com.ymttest.database.sharding.db.sharding.model.MainOrderPo;
import com.ymttest.database.sharding.db.sharding.model.OrderBizLogPo;
import com.ymttest.database.sharding.db.sharding.model.OrderBizPo;
import com.ymttest.database.sharding.db.sharding.model.OrderCouponDetailPo;
import com.ymttest.database.sharding.db.sharding.model.OrderDetailPo;
import com.ymttest.database.sharding.db.sharding.model.OrderDetailPromotionPo;
import com.ymttest.database.sharding.db.sharding.model.OrderDetailSubCodePo;
import com.ymttest.database.sharding.db.sharding.model.OrderDetailSubPo;
import com.ymttest.database.sharding.db.sharding.model.OrderPo;
import com.ymttest.database.sharding.db.sharding.model.OrderTravelerPo;
import com.ymttest.database.sharding.db.sharding.model.PickInStorePo;
import com.ymttest.database.sharding.db.sharding.model.ShenqiProxyChainPo;
import com.ymttest.database.sharding.db.sharding.model.ShenqiSellerProfitPo;
import com.ymttest.database.sharding.db.sqlwapper.OrderShardingWapper;
import com.ymttest.database.sharding.db.sqlwapper.OrderWapper;
import com.ymttest.database.sqlwapper.DGUserWapper;
import com.ymttest.database.sqlwapper.shenqi.SqliveOrderDetailWrapper;
import com.ymttest.utils.DataUtil;
import com.ymttest.utils.constant.ECode;

public class DGSQPlaceOrderVerifyService {
	
	private PlaceOrderReq placeOrderReq;
	private PlaceOrderCall placeorderCall;
	
	private OrderShardingWapper orderShardingWapper = new OrderShardingWapper();
	
	private static OrderWapper orderWapper = new OrderWapper();
	private static SqliveOrderDetailWrapper sqliveOrderDetailWrapper = new SqliveOrderDetailWrapper();
	
	private static long multiCDFCodeGoodsOwnerId = ShenqiUserSet.multiCDFCodeGoodsOwnerId;

	public DGSQPlaceOrderVerifyService(PlaceOrderReq placeOrderReq,
			PlaceOrderCall placeorderCall) {

		this.placeOrderReq = placeOrderReq;
		this.placeorderCall = placeorderCall;
	}

	private MainOrder buildOrder() throws Exception {

		MainOrder mainOrder = new MainOrder();

		// 各订单分摊折扣的权重
		List<BigDecimal> orderWeightsDiscount = new ArrayList<BigDecimal>();
		
		// 各订单分摊积分抵扣金额的权重
		List<BigDecimal> orderWeightsIntegralDeduction = new ArrayList<BigDecimal>();

		// 所有订单
		List<Order> allOrders = new ArrayList<Order>();

		String currency = Utils.nullIsCNY(placeOrderReq.getCurrency());
		
		// 整个支付单的店主总毛利润
		BigDecimal totalProxyProfit = BigDecimal.ZERO;

		for (OrderGroupVo groupVo : placeOrderReq.getOrderGroups()) {

			OrderGroup group = new OrderGroup();

			group.setOrderGroupVo(groupVo);
			mainOrder.getOrderGroups().add(group);

			BigDecimal totalProductPriceInSellerCoupon = BigDecimal.ZERO;
			
			int orderCount = 0;

			BigDecimal serviceRate = group.getOrderGroupVo().getServiceRate();
			
			Boolean isCDFCoupon = false;
			
			List<CouponVo> sellerCoupons = null;
			
			CouponVo sellerCoupon = groupVo.getSellerCoupon();
			int couponMainType = 0;
			
			// 中免不使用优惠券叠加
			if (null != sellerCoupon) {
				
				couponMainType = Utils.zeroIfNull(sellerCoupon
						.getCouponMainType());
				sellerCoupons = new ArrayList<>();

				isCDFCoupon = SqTradingCallService.isCDFCoupon(Utils
						.zeroIfNull(sellerCoupon.getCouponSource()));

				sellerCoupons.add(sellerCoupon);
			}

			if (null != groupVo.getSellerCoupons()) {

				// CouponMainType只可能有一种情况
				couponMainType = Utils.zeroIfNull(groupVo.getSellerCoupons()
						.get(0).getCouponMainType());

				if (null == sellerCoupons)
					sellerCoupons = new ArrayList<>();

				for (CouponVo c : groupVo.getSellerCoupons()) {

					isCDFCoupon = SqTradingCallService.isCDFCoupon(Utils
							.zeroIfNull(c.getCouponSource()));
					sellerCoupons.add(c);
				}
			}

			for (OrderVo orderVo : groupVo.getOrders()) {

				Order order = new Order();

				order.setOrderVo(orderVo);

				order.setSellerId(groupVo.getSellerId());
				order.setCouponMainType(couponMainType);

				allOrders.add(order);

				order.setCurrency(currency);
				order.setCurrencySymbol(placeOrderReq.getCurrencySymbol());

				BigDecimal orderFreight = BigDecimal.ZERO;
				
				BigDecimal orderGrossProfit = BigDecimal.ZERO;

				orderCount = orderCount + 1;
				int orderItemCount = 0;
				Boolean afterAcctivityFinishAccept = null;
				BigDecimal totalProductPrice = BigDecimal.ZERO;
				
				// 如果是兑换券
				if (sellerCoupons != null)
					sellerCoupon = sellerCoupons.get(0);
				
				if (null != sellerCoupons) {
					for (CouponVo sCoupon : sellerCoupons) {
						if (sCoupon.getCouponType() == 5) {

							String applianceTargets = sCoupon
									.getApplianceTargets().get(0);

							OrderItemVo exchangeCouponOrderItemVo = orderVo
									.getOrderItems()
									.stream()
									.filter(orderItems -> orderItems
											.getCatalogId().equalsIgnoreCase(
													applianceTargets))
									.findAny().orElse(null);

							OrderItemVo orderItemVo = null;

							if (null != exchangeCouponOrderItemVo) {
								if (exchangeCouponOrderItemVo.getProductNum() > 1) {

									orderItemVo = (OrderItemVo) exchangeCouponOrderItemVo
											.clone();
									exchangeCouponOrderItemVo
											.setProductNum(exchangeCouponOrderItemVo
													.getProductNum() - 1);

									orderItemVo.setCatalogId("speecc"
											+ exchangeCouponOrderItemVo
													.getCatalogId());
									orderItemVo.setProductNum(1);

									// 费率分摊
									BigDecimal[] freightWeight = new BigDecimal[2];

									freightWeight[0] = exchangeCouponOrderItemVo
											.getProductPrice()
											.multiply(
													new BigDecimal(
															exchangeCouponOrderItemVo
																	.getProductNum()));
									freightWeight[1] = orderItemVo
											.getProductPrice();

									BigDecimal freight[] = Utils
											.apportionByWeights(Utils
													.zeroIfNull(orderItemVo
															.getFreight()),
													freightWeight);

									exchangeCouponOrderItemVo
											.setFreight(freight[0]);
									orderItemVo.setFreight(freight[1]);

									orderVo.getOrderItems().add(orderItemVo);
								} else {

									orderItemVo = exchangeCouponOrderItemVo;
									orderItemVo.setCatalogId("speecc"
											+ exchangeCouponOrderItemVo
													.getCatalogId());
								}
							}
						}
					}
				}
				
				// 是否为分销订单
				boolean isInheritedOrder = false;
				
				// 是否为直销订单
				boolean isDirectSellOrder = order.getSellerId() == orderVo
						.getGoodsOwnerId();
				
				if (!isDirectSellOrder) {
					
					isInheritedOrder = GodmchManageCallService
							.isInheritedAgent(order.getSellerId());
					
					order.setIsProxy(true);
					order.setIsInherited(isInheritedOrder);
				}
				
				for (OrderItemVo orderItemVo : orderVo.getOrderItems()) {

					BigDecimal productPriceInSellerCoupon = BigDecimal.ZERO;

					OrderItem orderItem = new OrderItem();

					orderItem.setItemVo(orderItemVo);

					order.getOrderItems().add(orderItem);

					if (Utils.falseIfNull(orderItemVo
							.getFullReductionFreeFreight()))
						orderFreight = orderFreight.add(BigDecimal.ZERO);
					else
						orderFreight = orderFreight.add(Utils
								.zeroIfNull(orderItemVo.getFreight()));

					// 累计订单的总成交价
					BigDecimal productPrice = orderItemVo
							.getProductPrice()
							.multiply(
									new BigDecimal(orderItemVo.getProductNum()));
					BigDecimal proxyPrice = null;

					totalProductPrice = totalProductPrice.add(productPrice);

					// 如果是直销商
					if (isDirectSellOrder) {

						proxyPrice = BigDecimal.ZERO;
						orderItem.setServiceRate(serviceRate);
					} else {
						
						List<ShenqiProxyChainPo> shenqiProxyChain = new ArrayList<>();
						boolean isPlatformSupplierOrder = false;

						if (isInheritedOrder) {

							shenqiProxyChain = SqTradingProductService
									.getInheritedProxyChainInfo(
											orderItemVo.getCatalogId(),
											order.getSellerId());

							proxyPrice = shenqiProxyChain.get(
									shenqiProxyChain.size() - 1)
									.getFromParentPrice();
						} else {

							shenqiProxyChain = SqTradingProductService
									.getProxyChainInfoList(orderItemVo
											.getCatalogId(), order.getSellerId());

							proxyPrice = shenqiProxyChain.get(
									shenqiProxyChain.size() - 1)
									.getFromParentPrice();

							isPlatformSupplierOrder = GodmchManageCallService
									.queryPlatformBindRelation(orderVo
											.getGoodsOwnerId(),
											shenqiProxyChain.get(1)
													.getSellerId());
						}

						orderItem.setShenqiProxyChain(shenqiProxyChain);
						order.setIsPlatformSupplierOrder(isPlatformSupplierOrder);
					}

					// 获得该商品的毛利润
					BigDecimal productProxyProfit = orderItemVo
							.getProductPrice()
							.subtract(proxyPrice)
							.multiply(
									new BigDecimal(orderItemVo.getProductNum()));

					orderItem.setOrderItemGrossProfit(productProxyProfit);

					order.getOrderItemWeightsOnFreight().add(totalProductPrice);

					order.setTotalProductPrice(totalProductPrice);

					int couponCount = 0;

					if (null != sellerCoupons) {
						if (sellerCoupons.size() == 0) {

							order.getOrderItemWeightsOnSellerCoupon().add(
									BigDecimal.ZERO);
							productPriceInSellerCoupon = BigDecimal.ZERO;
						} else {
							
							Boolean addTotalProductPriceInSellerCoupon = false;
							
							for (CouponVo c : sellerCoupons) {
								if (c != null
										&& couponApplicable(orderItemVo, c)
										&& !Utils.falseIfNull(orderItemVo
												.getExchangeBuy())) {

									couponCount = couponCount + 1;
									
									if (isCDFCoupon) {

										order.setSellerCouponCode(c.getCouponCode());
										order.setSellerCouponSource(c
												.getCouponSource());
										order.setSellerCouponType(c.getCouponType());
									} else {

										// 如果是多个优惠券，则订单上只保留第一张券的信息
										order.setSellerCouponCode(sellerCoupons
												.get(0).getCouponCode());
										order.setSellerCouponSource(sellerCoupons
												.get(0).getCouponSource());
										order.setSellerCouponType(couponCount > 1 ? -1
												: sellerCoupon.getCouponType());

										productPriceInSellerCoupon = productPrice;
										
										if (!addTotalProductPriceInSellerCoupon) {
											
											// 订单中适用商家优惠券的成交价总额
											order.setTotalProductPriceInSellerCoupon(order
													.getTotalProductPriceInSellerCoupon()
													.add(productPriceInSellerCoupon));

											totalProductPriceInSellerCoupon = totalProductPriceInSellerCoupon
													.add(productPriceInSellerCoupon);
											order.getOrderItemWeightsOnSellerCoupon()
													.add(productPrice);
										}

										addTotalProductPriceInSellerCoupon = true;
									}
								}
							}
						}
					}
					
					totalProxyProfit = totalProxyProfit.add(productProxyProfit);
					orderGrossProfit = orderGrossProfit.add(productProxyProfit);
					
					orderItemCount = orderItemCount + 1;

					if (placeOrderReq.getDiscount() != null) {

						// 商品分摊折扣的权重按照商品价格
						order.getOrderItemWeightsOnDiscount().add(
								productPrice);
					}

					if (null != orderItemVo.getActivity()) {

						if (Utils.falseIfNull(orderItemVo.getActivity()
								.getAfterActivityFinishAccept())
								|| Utils.falseIfNull(afterAcctivityFinishAccept)) {
							afterAcctivityFinishAccept = true;
						} else {
							afterAcctivityFinishAccept = false;
						}
					} else
						afterAcctivityFinishAccept = Utils
								.falseIfNull(afterAcctivityFinishAccept);
				} // end orderItems

				order.setFreight(orderFreight);
				order.setGoodsOwnerId(orderVo.getGoodsOwnerId());
				order.setShenqiLogisticsType(orderVo.getShenqiLogisticsType());
				order.setShenqiIdCardRequirement(orderVo
						.getShenqiIdCardRequirement());
				order.setAfterAcctivityFinishAccept(afterAcctivityFinishAccept);
				order.setOrderGrossProfit(orderGrossProfit);
				
				group.getOrderWeightsOnSellerCoupon().add(
						order.getTotalProductPriceInSellerCoupon());
				
				group.getOrders().add(order);

			} // end orders
			
			// 分摊商家优惠活动金额
			apportionSellerPromotions(group, currency);
			
			// 计算区域折扣到订单
			calcRegionDiscountToOrder(group, currency);

			// 分摊区域折扣到订单项
			apportionRegionDiscountToOrderItem(group, currency);
			
			int index = 0;
			
			if (null != sellerCoupons) {
				for (CouponVo sCoupon : sellerCoupons) {
					if (sCoupon != null) {
						if (isCDFCoupon) {

							List<OrderItem> orderItemList = new ArrayList<>();
							List<OrderVoForCdfCoupon> orderVoList = new ArrayList<>();

							for (Order order : group.getOrders()) {

								OrderVoForCdfCoupon orderVoForCdfCoupon = new OrderVoForCdfCoupon();

								List<ProductVoForCdfCoupon> productVoList = new ArrayList<>();

								for (OrderItem orderItem : order.getOrderItems()) {

									ProductVoForCdfCoupon productVoForCdfCoupon = new ProductVoForCdfCoupon();

									OrderItemVo orderItemVo = orderItem.getItemVo();

									BigDecimal productPriceExcludeSellerPromotionAndRegionDiscount = orderItemVo
											.getProductPrice()
											.multiply(
													new BigDecimal(orderItemVo
															.getProductNum()))
											.subtract(
													Utils.zeroIfNull(orderItem
															.getSellerPromotionAmount()))
											.subtract(
													Utils.zeroIfNull(orderItem
															.getRegionDiscountValue()))
											.divide(new BigDecimal(
													orderItemVo.getProductNum()),
													2, BigDecimal.ROUND_DOWN);

									productVoForCdfCoupon.setCatalogId(orderItemVo
											.getCatalogId());
									productVoForCdfCoupon
											.setPrice(productPriceExcludeSellerPromotionAndRegionDiscount);
									productVoForCdfCoupon.setProductId(orderItemVo
											.getProductId());
									productVoForCdfCoupon.setProductNum(orderItemVo
											.getProductNum());
									productVoForCdfCoupon.setSkuId(orderItemVo
											.getSku());
									productVoForCdfCoupon.setSubProduct(orderItemVo
											.isSubProduct());
									productVoForCdfCoupon
											.setExchangeBuy(orderItemVo
													.getExchangeBuy());
									productVoForCdfCoupon
											.setDomesticProduct(orderItemVo
													.getDomesticProduct());

									productVoList.add(productVoForCdfCoupon);

									orderItemList.add(orderItem);
								}

								orderVoForCdfCoupon.setProductVoList(productVoList);

								orderVoList.add(orderVoForCdfCoupon);
							}

							CdfDeductCouponBeforePlaceReq cdfDeductCouponBeforePlaceReq = new CdfDeductCouponBeforePlaceReq();

							// 领取cdf优惠券
							CDFMemberService.getCdfCoupon(groupVo
									.getSellerCoupon().getCouponType(), groupVo
									.getSellerId() == 502665591 ? 2 : 1,
									placeOrderReq.getUserId());

							groupVo.getSellerCoupon().setCouponCode(
									CDFMemberService.getLatestUnuseCdfCoupon(
											placeOrderReq.getUserId(),
											groupVo.getSellerId()));

							cdfDeductCouponBeforePlaceReq.setCouponVo(groupVo
									.getSellerCoupon());
							cdfDeductCouponBeforePlaceReq.setSellerId(groupVo
									.getSellerId());
							cdfDeductCouponBeforePlaceReq.setUserId(placeOrderReq
									.getUserId());
							cdfDeductCouponBeforePlaceReq
									.setOrderVoList(orderVoList);
							cdfDeductCouponBeforePlaceReq.setCurrency(Utils
									.nullIsCNY(placeOrderReq.getCurrency()));

							CdfDeductCouponBeforePlaceResp cdfDeductCouponBeforePlaceResp = SqTradingCallService
									.cdfDeductCouponBeforePlace(cdfDeductCouponBeforePlaceReq);

							// 分摊中免优惠券到订单项
							apportionCDFCouponToOrderItem(orderItemList,
									cdfDeductCouponBeforePlaceResp
											.getCouponAmountVoList());

							for (Order order : group.getOrders()) {

								BigDecimal orderCouponValue = order.getOrderItems()
										.stream()
										.map(o -> o.getSellerCouponValue())
										.reduce(BigDecimal.ZERO, BigDecimal::add);
								order.setSellerCouponValue(orderCouponValue);
							}
						} else {

							if (sCoupon.getCouponType() == 5) {

							} else {
		
								// 分摊商家优惠券
								if (totalProductPriceInSellerCoupon
										.compareTo(sellerCoupon.getCouponValue()) <= 0) {
									throw new IllegalArgumentException(
											"商家适用优惠券的商品成交价总额必须大于商家优惠券总额:"
													+ groupVo.getSellerId());
								}
							}

							// 分摊商家优惠券到订单
							apportionSellerCouponToOrder(group, currency, sCoupon, index);

							// 分摊商家优惠券到订单项
							apportionSellerCouponToOrderItem(group, currency, index);
							
							totalProductPriceInSellerCoupon = totalProductPriceInSellerCoupon.subtract(sCoupon.getCouponValue());
						}
						
						index = index + 1;
					}
				}
			}
		} // end groups
		
		List<BigDecimal> productPriceWeights = new ArrayList<BigDecimal>();

		// 分摊折扣
		if (placeOrderReq.getDiscount() != null) {
			
			for (Order order : allOrders) {
				
				productPriceWeights.add(order.getTotalProductPrice());
				
				if (order.getIsProxy()) {
					
					orderWeightsDiscount.add(order.getOrderGrossProfit());
				} else {
					
					orderWeightsDiscount.add(order.getTotalProductPrice());
				}
			}
			
			// 如果代理订单没有利润
			if (orderWeightsDiscount.stream().reduce(BigDecimal::add)
					.orElse(BigDecimal.ZERO).compareTo(BigDecimal.ZERO) <= 0) {
				
				orderWeightsDiscount = productPriceWeights;
			}

			boolean isNegate = placeOrderReq.getDiscount().compareTo(
					BigDecimal.ZERO) == -1 ? true : false;

			apportionOrderDiscountToOrder(allOrders,
					placeOrderReq.getDiscount(), orderWeightsDiscount,
					currency, isNegate);

			apportionOrderDiscountToOrderItem(allOrders, currency, isNegate);
		}
		
		calcExpectedOrderTaxFee(allOrders, placeOrderReq.getAddress());
		
		// 分摊积分，经讨论，先摊积分抵扣金额，再将金额换算成积分
		if (placeOrderReq.getIntegral() != null) {

			Long shopId = placeOrderReq.getOrderGroups().get(0).getSellerId();
			
			// 中免大会员使用积分，不关心分摊
			if (isCDFMember(shopId)) {
				return mainOrder;
			} else {
				
				// 使用的积分超过限额时，无法下单；这里只需要获取积分策略，计算下单使用的积分抵扣金额
				CalcOrderCreditResp calcOrderCreditResp = GodPointsService
						.calcOrderCredit(new BigDecimal("0.01"),
								Utils.nullIsCNY(currency), shopId,
								placeOrderReq.getUserId());

				BigDecimal integralAmount = GodPointsService.calcOrderCreditAmount(
						calcOrderCreditResp, placeOrderReq.getIntegral());

				for (Order order : allOrders) {
					
					BigDecimal orderNetProfitWeight = BigDecimal.ZERO;
					
					for (OrderItem orderItem : order.getOrderItems()) {
						
						BigDecimal orderItemNetProfit = BigDecimal.ZERO;
						BigDecimal orderItemNetProfitWeight = BigDecimal.ZERO;

						// 直销订单
						if (!order.getIsProxy()) {

							BigDecimal freight = Utils.falseIfNull(orderItem
									.getItemVo().getFullReductionFreeFreight()) ? BigDecimal.ZERO
									: orderItem.getItemVo().getFreight();

							// 店主的商品纯利润
							orderItemNetProfit = orderItem
									.getOrderItemGrossProfit()
									.add(Utils.zeroIfNull(orderItem
											.getDiscount()))
									.add(Utils.zeroIfNull(freight))
									.add(Utils.zeroIfNull(orderItem.getTaxFee()))
									.subtract(
											Utils.zeroIfNull(orderItem
													.getSellerCouponValue()))
									.subtract(
											Utils.zeroIfNull(orderItem
													.getSellerPromotionAmount()))
									.subtract(
											Utils.zeroIfNull(orderItem
													.getYmatouCouponValue()))
									.subtract(
											Utils.zeroIfNull(orderItem
													.getRegionDiscountValue()));
						} else if (order.getIsInherited()) {

							// 店主的商品纯利润
							orderItemNetProfit = orderItem
									.getOrderItemGrossProfit();
						} else {

							// 代理订单
							BigDecimal freight = Utils.falseIfNull(orderItem.getItemVo()
									.getFullReductionFreeFreight()) ? orderItem.getItemVo().getFreight().negate()
									: BigDecimal.ZERO;

							// 店主的商品纯利润
							orderItemNetProfit = orderItem
									.getOrderItemGrossProfit()
									.add(Utils.zeroIfNull(freight))
									.add(Utils.zeroIfNull(orderItem
											.getDiscount()))
									.add(Utils.zeroIfNull(orderItem.getTaxFee()))
									.subtract(
											Utils.zeroIfNull(orderItem
													.getSellerCouponValue()))
									.subtract(
											Utils.zeroIfNull(orderItem
													.getSellerPromotionAmount()))
									.subtract(
											Utils.zeroIfNull(orderItem
													.getYmatouCouponValue()))
									.subtract(
											Utils.zeroIfNull(orderItem
													.getRegionDiscountValue()));
						}

						if (orderItemNetProfit.compareTo(BigDecimal.ZERO) == 1)
							orderItemNetProfitWeight = orderItemNetProfit;
									
						order.getOrderItemWeightsOnIntegralDeduction().add(orderItemNetProfitWeight);
					}
				
					// 订单纯利润
					BigDecimal orderNetProfit = order.getOrderItems().stream()
							.map(OrderItem::getOrderItemGrossProfit)
							.reduce(BigDecimal.ZERO, BigDecimal::add);
					
					if (orderNetProfit.compareTo(BigDecimal.ZERO) == 1)
						orderNetProfitWeight = orderNetProfit;
					
					orderWeightsIntegralDeduction.add(orderNetProfitWeight);
				}
				
				// 各订单分摊积分抵扣金额的权重
				List<BigDecimal> orderWeightsIntegral = apportionOrderIntegralDeductionToOrder(allOrders, integralAmount,
						orderWeightsIntegralDeduction, currency);
				apportionOrderIntegralDeductionToOrderItem(allOrders, currency);

				apportionOrderIntegralToOrder(allOrders, new BigDecimal(
						placeOrderReq.getIntegral()), orderWeightsIntegral);
				apportionOrderIntegralToOrderItem(allOrders);
			}
		}

		return mainOrder;
	}

	public static boolean couponApplicable(OrderItemVo orderItem,
			CouponVo coupon) {
		switch (coupon.getApplianceType()) {
		case ALL:
			return true;
		case SPEC_RODUCT:
			return coupon.getApplianceTargets().contains(
					orderItem.getProductId());
		case SPEC_CATALOG:
			if (coupon.getCouponType() == 5)
				return coupon.getApplianceTargets().contains(
						orderItem.getCatalogId().substring(6));
		default:
			throw new IllegalArgumentException("未知的优惠券适用类型:"
					+ coupon.getApplianceType());
		}
	}

	/**
	 * 分摊商家优惠
	 *
	 * @param group
	 */
	private static void apportionSellerPromotions(OrderGroup group,
			String currency) {
		if (!CollectionUtils.isEmpty(group.getOrderGroupVo()
				.getSellerPromotionApportions())) {
			group.distributeSellerPromotionApportions(currency);
		}
	}

	/**
	 * 分摊商家优惠券到订单
	 */
	private static void apportionSellerCouponToOrder(OrderGroup g,
			String currency, CouponVo sellerCouponVo, int index) {
		
		Logger.comment(String.format("分摊第%s张优惠券到订单", index + 1));
		
		if (sellerCouponVo.getCouponType() == 5) {

			BigDecimal[] couponValues = g.getOrderWeightsOnSellerCoupon()
					.toArray(new BigDecimal[0]);

			for (int i = 0; i < couponValues.length; i++) {

				g.getOrders().get(i).setSellerCouponValue(couponValues[i]);

				OrderCouponDetailPo orderCouponDetailPo = new OrderCouponDetailPo();

				orderCouponDetailPo.setCouponCode(sellerCouponVo
						.getCouponCode());
				orderCouponDetailPo.setCouponSource(sellerCouponVo
						.getCouponSource());
				orderCouponDetailPo.setCouponType(5);
				orderCouponDetailPo.setDeleted(false);
				orderCouponDetailPo.setAmount(couponValues[i]);

				if (couponValues[i].compareTo(BigDecimal.ZERO) == 1)
					g.getOrders()
							.get(i)
							.setOrderCouponDetailList(
									Arrays.asList(orderCouponDetailPo));				
			}
		} else {

			BigDecimal[] result = Utils.apportionByWeights3(sellerCouponVo
					.getCouponValue(), g.getOrderWeightsOnSellerCoupon()
					.toArray(new BigDecimal[0]), currency);
			
			List<BigDecimal> newOrderWeightsOnSellerCoupon = new ArrayList<>();

			for (int i = 0; i < result.length; i++) {
				
				g.getOrders()
						.get(i)
						.setSellerCouponValue(
								Utils.zeroIfNull(
										g.getOrders().get(i)
												.getSellerCouponValue()).add(
										result[i]));
				
				OrderCouponDetailPo orderCouponDetailPo = new OrderCouponDetailPo();

				orderCouponDetailPo.setCouponCode(sellerCouponVo
						.getCouponCode());
				orderCouponDetailPo.setCouponSource(sellerCouponVo
						.getCouponSource());
				orderCouponDetailPo.setCouponType(sellerCouponVo.getCouponType());
				orderCouponDetailPo.setDeleted(false);
				orderCouponDetailPo.setAmount(result[i]);

				if (null == g.getOrders().get(i).getOrderCouponDetailList()) {

					g.getOrders()
							.get(i)
							.setOrderCouponDetailList(
									Arrays.asList(orderCouponDetailPo));
				} else {

					List<OrderCouponDetailPo> details = new ArrayList<>(g
							.getOrders().get(i).getOrderCouponDetailList());

					details.add(orderCouponDetailPo);

					g.getOrders().get(i).setOrderCouponDetailList(details);
				}
				
				newOrderWeightsOnSellerCoupon.add(g
						.getOrderWeightsOnSellerCoupon().get(i)
						.subtract(result[i]));
			}
			
			g.setOrderWeightsOnSellerCoupon(newOrderWeightsOnSellerCoupon);
		}
	}

	/**
	 * 分摊商家优惠券到订单商品
	 * 
	 * @param g
	 */
	public static void apportionSellerCouponToOrderItem(OrderGroup g,
			String currency, int index) {
		
		Logger.comment(String.format("分摊第%s张优惠券到商品项", index + 1));

		for (Order order : g.getOrders()) {
			if (order.getSellerCouponCode() != null) {

				if (order.getSellerCouponType() == 5) {

					for (int i = 0; i < order.getOrderItems().size(); i++) {
						
						if (order.getOrderItems().get(i).getItemVo()
								.getCatalogId().startsWith("speeccc"))
							order.getOrderItems()
									.get(i)
									.setSellerCouponValue(
											order.getOrderItems().get(i)
													.getItemVo()
													.getProductPrice());
					}
				} else {

					int orderItemSize = order.getOrderItems().size();
					List<BigDecimal> maxLimits = new ArrayList<BigDecimal>(orderItemSize);

					for (int i = 0; i < orderItemSize; i++) {

						OrderItem orderItem = order.getOrderItems().get(i);

						if (orderItem.getItemVo().getExchangeBuy())
							continue;

						BigDecimal temp = order.getOrderItemWeightsOnSellerCoupon().get(i)
								.subtract(orderItem.getSellerCouponValue())
								.add(orderItem.getItemVo().getFullReductionFreeFreight() ?
										BigDecimal.ZERO : orderItem.getItemVo().getFreight())
								.subtract(orderItem.getSellerPromotionAmount())
								.subtract(orderItem.getRegionDiscountValue());

						maxLimits.add(temp);
					}

					Logger.info(String.format("优惠券order_detail分摊数据：total:%s, weights:%s, maxLimits:%s, currency:%s",
							order.getSellerCouponValue(),
							order.getOrderItemWeightsOnSellerCoupon(),
							maxLimits,
							currency));

					BigDecimal[] result = Utils.apportion(
							order.getSellerCouponValue(),
							order.getOrderItemWeightsOnSellerCoupon().toArray(new BigDecimal[0]),
							maxLimits.toArray(new BigDecimal[0]),
							currency);

					for (int i = 0; i < result.length; i++) {
						order.getOrderItems().get(i)
								.setSellerCouponValue(result[i]);
					}
				}
			}
		}
	}
	
	/**
	 * 分摊CDF优惠券到订单商品
	 * 
	 * @param
	 */
	private static void apportionCDFCouponToOrderItem(
			List<OrderItem> orderItemList, List<CouponAmountVo> couponAmountList) {

		for (int i = 0; i < couponAmountList.size(); i++) {

			orderItemList.get(i).setSellerCouponValue(
					couponAmountList.get(i).getDeductionAmount());
		}
	}

	/**
	 * 分摊平台折扣到订单
	 * 
	 * @param orders
	 * @param discountValue
	 * @param orderWeights
	 */
	public static void apportionOrderDiscountToOrder(List<Order> orders,
			BigDecimal discountValue, List<BigDecimal> orderWeights,
			String currency, boolean isNegate) {

		List<BigDecimal> maxLimits = new ArrayList<BigDecimal>();

		for (Order o : orders) {
			maxLimits.add(o.calcMaxPromotionLeftAndFreight());
		}

		Logger.info(String.format("订单折扣order分摊数据：total:%s, weights:%s, currency:%s",
				discountValue.abs(),
				orderWeights,
				currency));

//		BigDecimal[] result = Utils.apportionByWeightsWithCurrency(discountValue.abs(),
//				orderWeights.toArray(new BigDecimal[0]), currency);

		BigDecimal[] result = null;

		if (discountValue.compareTo(BigDecimal.ZERO) == -1)
			result = Utils.apportionByWeightsAndMaxLimit(
					discountValue.abs(), orderWeights.toArray(new BigDecimal[0]),
					maxLimits.toArray(new BigDecimal[0]), currency);
		else
			result = Utils.apportionByWeightsAndMaxLimit(
					discountValue.abs(), orderWeights.toArray(new BigDecimal[0]),
					maxLimits.toArray(new BigDecimal[0]), "JPY");

		
		for (int i = 0; i < result.length; i++) {
			orders.get(i).setOrderDiscount(isNegate ? result[i].negate() : result[i]);
		}
	}
	
	/**
	 * 分摊折扣到订单商品
	 * 
	 * @param orders
	 */
	public static void apportionOrderDiscountToOrderItem(List<Order> orders,
			String currency, boolean isNegate) {

		for (Order order : orders) {
			BigDecimal[] result = Utils.apportionByWeightsWithCurrency(order
					.getOrderDiscount().abs(), order.getOrderItemWeightsOnDiscount()
					.toArray(new BigDecimal[0]), currency);

			for (int i = 0; i < result.length; i++) {
				order.getOrderItems().get(i).setDiscount(isNegate ? result[i].negate() : result[i]);
			}
		}
	}
	
	/**
	 * 分摊积分抵扣金额到订单
	 * 
	 * @param orders
	 * @param integralDeductionValue
	 * @param orderWeights
	 */
	public static List<BigDecimal> apportionOrderIntegralDeductionToOrder(List<Order> orders,
			BigDecimal integralDeductionValue, List<BigDecimal> orderWeights,
			String currency) {

		List<BigDecimal> maxLimits = new ArrayList<BigDecimal>();
		List<BigDecimal> orderWeightsIntegral = new ArrayList<BigDecimal>();
		
		for (Order o : orders) {
			maxLimits.add(o.calcMaxPromotionLeftAndFreight());
		}
		
		BigDecimal[] result;
		
		result = Utils.apportionByWeightsWithCurrency(integralDeductionValue, orderWeights.toArray(new BigDecimal[0]),
				currency);
		
		for (int i = 0; i < result.length; i++) {
			orders.get(i).setOrderIntegralDeduction(result[i]);
			orderWeightsIntegral.add(result[i]);
		}
		
		return orderWeightsIntegral;
	}
	
	/**
	 * 分摊积分抵扣金额到商品
	 * 
	 * @param orders
	 */
	public static void apportionOrderIntegralDeductionToOrderItem(List<Order> orders,
			String currency) {

		for (Order order : orders) {

			Logger.info(String.format("积分余额order_detail分摊数据：total:%s, weights:%s, currency:%s",
					order.getOrderIntegralDeduction(),
					order.getOrderItemWeightsOnIntegralDeduction(),
					currency));

			BigDecimal[] result = Utils.apportion(order.getOrderIntegralDeduction(),
					order.getOrderItemWeightsOnIntegralDeduction().toArray(new BigDecimal[0]),
					order.getOrderItemWeightsOnIntegralDeduction().toArray(new BigDecimal[0]),
					currency);
			
			for (int i = 0; i < result.length; i++) {
				order.getOrderItems().get(i).setIntegralDeduction(result[i]);
				order.getOrderItemWeightsOnIntegral().add(result[i]);
			}
		}
	}
	
	/**
	 * 分摊积分到订单
	 * 
	 * @param orders
	 * @param integralValue
	 * @param orderWeights
	 */
	public static List<BigDecimal> apportionOrderIntegralToOrder(List<Order> orders,
			BigDecimal integralValue, List<BigDecimal> orderWeights) {

//		List<BigDecimal> maxLimits = new ArrayList<BigDecimal>();
		List<BigDecimal> orderWeightsIntegralDeduction = new ArrayList<BigDecimal>();
		
//		for (Order o : orders) {
//			maxLimits.add(o.calcMaxPromotionLeftAndFreight());
//		}
		
		BigDecimal[] result = null;
		
		result = Utils.apportionIntegralByWeightsWithCurrency(integralValue, orderWeights.toArray(new BigDecimal[0]));
		
		orders = orders
				.stream()
				.sorted(Comparator.comparing(Order::getOrderIntegralDeduction)
						.reversed()).collect(Collectors.toList());
		
		for (int i = 0; i < result.length; i++) {
			orders.get(i).setOrderIntegral(result[i].longValue());
			
//			orderWeightsIntegralDeduction.add(result[i]);
		}
		
		return orderWeightsIntegralDeduction;
	}
	
	/**
	 * 分摊积分抵扣到商品
	 * 
	 * @param orders
	 */
	public static void apportionOrderIntegralToOrderItem(List<Order> orders) {
		
		for (Order order : orders) {
			
			BigDecimal[] result = Utils.apportionIntegralByWeightsWithCurrency(new BigDecimal(order
					.getOrderIntegral()), order.getOrderItemWeightsOnIntegral()
					.toArray(new BigDecimal[0]));
			
			 List<OrderItem> orderItems = order.getOrderItems()
					.stream()
					.sorted(Comparator
							.comparing(OrderItem::getIntegralDeduction).reversed()).collect(Collectors.toList());
			
			for (int i = 0; i < result.length; i++) {
				orderItems.get(i).setIntegral(result[i].longValue());
//				order.getOrderItemWeightsOnIntegralDeduction().add(result[i]);
			}
		}
	}
	
	/**
	 * 计算区域折扣到订单
	 */
	private void calcRegionDiscountToOrder(OrderGroup g,
			String currency) {
		
		int scale = 0;
		
		if (null == placeOrderReq.getCurrency())
			scale = 2;
		else if (null != placeOrderReq.getCurrency()
				&& placeOrderReq.getCurrency().equalsIgnoreCase(
						"JPY"))
			scale = 0;
		else
			scale = 2;
		
		// 订单上区域折扣权重
		for (Order order : g.getOrders()) {

			BigDecimal regionDiscount = BigDecimal.ZERO;

			// 区域折扣金额
			if (Utils.zeroIfNull(order.getOrderVo().getRegionDiscountRatio())
					.compareTo(BigDecimal.ZERO) == 1) {

				BigDecimal regionDiscountRate = BigDecimal.ONE
						.subtract(Utils.zeroIfNull(
								order.getOrderVo().getRegionDiscountRatio())
								.divide(BigDecimal.TEN, 2,
										BigDecimal.ROUND_DOWN));
				
				if (Utils.zeroIfNull(order.getSellerCouponType()) == 5)
					regionDiscount = order
							.getTotalProductPrice()
							.subtract(order.getSellerPromotionAmount())
							.subtract(
									order.getTotalProductPriceInSellerCoupon())
							.multiply(regionDiscountRate)
							.setScale(scale, BigDecimal.ROUND_DOWN);
				else
					regionDiscount = order.getTotalProductPrice()
							.subtract(order.getSellerPromotionAmount())
							.multiply(regionDiscountRate)
							.setScale(scale, BigDecimal.ROUND_DOWN);
				

				order.setRegionDiscountValue(regionDiscount);
			} else
				order.setRegionDiscountValue(regionDiscount);
		}
	}

	/**
	 * 分摊区域折扣到订单商品
	 * 
	 * @param g
	 */
	private static void apportionRegionDiscountToOrderItem(OrderGroup g,
			String currency) {

		for (Order order : g.getOrders()) {
			
			// 订单项上区域折扣权重
			for (OrderItem orderItem : order.getOrderItems()) {

				if (Utils.zeroIfNull(order.getSellerCouponType()) == 5)
					order.getOrderItemWeightsOnRegionDiscount()
							.add(orderItem
									.getItemVo()
									.getProductPrice()
									.multiply(
											new BigDecimal(orderItem
													.getItemVo()
													.getProductNum()))
									.subtract(
											orderItem
													.getSellerPromotionAmount())
									.subtract(
											orderItem.getItemVo()
													.getProductPrice()));
				else
					order.getOrderItemWeightsOnRegionDiscount()
							.add(orderItem
									.getItemVo()
									.getProductPrice()
									.multiply(
											new BigDecimal(orderItem
													.getItemVo()
													.getProductNum()))
									.subtract(
											orderItem
													.getSellerPromotionAmount()));
			}
			
			if (Utils.zeroIfNull(order.getRegionDiscountValue()).compareTo(BigDecimal.ZERO) == 1) {

				Logger.info(String.format("区域折扣order_detail分摊数据：total:%s, weights:%s, currency:%s",
						order.getRegionDiscountValue(),
						order.getOrderItemWeightsOnRegionDiscount(),
						currency));

				BigDecimal[] result = Utils.apportion(
						order.getRegionDiscountValue(),
						order.getOrderItemWeightsOnRegionDiscount().toArray(new BigDecimal[0]),
						order.getOrderItemWeightsOnRegionDiscount().toArray(new BigDecimal[0]),
						currency);

				for (int i = 0; i < result.length; i++) {
					order.getOrderItems().get(i)
							.setRegionDiscountValue(result[i]);
				}
			}
		}
	}

	private void calcExpectedOrderTaxFee(List<Order> orders,
			String address) {

		int scale = 0;

		for (Order o : orders) {

			BigDecimal orderTaxFee = BigDecimal.ZERO;
			BigDecimal productTaxFee = BigDecimal.ZERO;

			for (OrderItem orderItem : o.getOrderItems()) {

				if (SqTradingCallService.isFreePerimeters(placeOrderReq
						.getAddress()))
					productTaxFee = BigDecimal.ZERO;
				else {

					if (null == placeOrderReq.getCurrency())
						scale = 2;
					else if (null != placeOrderReq.getCurrency()
							&& placeOrderReq.getCurrency().equalsIgnoreCase(
									"JPY"))
						scale = 0;
					else
						scale = 2;

					boolean fullReductionFreeFreight = Utils
							.falseIfNull(orderItem.getItemVo()
									.getFullReductionFreeFreight());
					
					productTaxFee = Utils
							.zeroIfNull(
									fullReductionFreeFreight ? BigDecimal.ZERO
											: orderItem.getItemVo()
													.getFreight())
							.divide(new BigDecimal(orderItem.getItemVo()
									.getProductNum()), 2, BigDecimal.ROUND_UP)
							.add(orderItem.getItemVo().getProductPrice())
							.add(Utils.zeroIfNull(orderItem.getDiscount())
									.divide(new BigDecimal(orderItem
											.getItemVo().getProductNum()), 2,
											BigDecimal.ROUND_UP))
							.subtract(
									Utils.zeroIfNull(
											orderItem.getSellerCouponValue())
											.divide(new BigDecimal(orderItem
													.getItemVo()
													.getProductNum()), 2,
													BigDecimal.ROUND_UP))
							.subtract(
									Utils.zeroIfNull(orderItem
											.getYmatouCouponValue()))
							.subtract(
									Utils.zeroIfNull(
											orderItem
													.getSellerPromotionAmount())
											.divide(new BigDecimal(orderItem
													.getItemVo()
													.getProductNum()), 2,
													BigDecimal.ROUND_UP))
							.subtract(
									Utils.zeroIfNull(orderItem.getItemVo()
											.getYmtPromotionAmount()))
							.subtract(
									Utils.zeroIfNull(
											orderItem.getRegionDiscountValue())
											.divide(new BigDecimal(orderItem
													.getItemVo()
													.getProductNum()), 2,
													BigDecimal.ROUND_UP))
							.multiply(
									Utils.zeroIfNull(orderItem.getItemVo()
											.getProdTaxRate()))
							.setScale(scale, BigDecimal.ROUND_HALF_UP);
					
					BigDecimal orderItemTaxFee = productTaxFee
							.multiply(new BigDecimal(orderItem.getItemVo()
									.getProductNum()));
					
					orderItem.setTaxFee(orderItemTaxFee);

					orderTaxFee = orderTaxFee.add(orderItemTaxFee);
				}
			}

			o.setTaxFee(orderTaxFee);
		}
	}

	private static BigDecimal calActualOrderTaxFee(
			List<OrderDetailPo> orderDetails) {

		BigDecimal taxFee = BigDecimal.ZERO;

		for (OrderDetailPo detailPo : orderDetails) {

			taxFee = taxFee.add(detailPo.getTaxFee().multiply(
					new BigDecimal(detailPo.getProductCount())));
		}

		return taxFee;
	}
	
	private static Boolean isCDFMember(Long shopId) {

		return SqTradingCallService.isCDFMember(shopId);
	}
	
	// 测试环境1小时以内为直播订单
	public static Boolean isLiveOrder(List<OrderItem> orderItems, Long orderId) {
		
		List<SqliveOrderDetail> sqliveOrderDetailList = sqliveOrderDetailWrapper
				.selectByOrderId(orderId);

		if (sqliveOrderDetailList.size() == 0) {
			
			SqTradingMqService.updateLiveOrder(false, orderId);
			
			return false;
		}	

		for (OrderItem orderItem : orderItems) {

			SqliveOrderDetail sqliveOrderDetail = sqliveOrderDetailList
					.stream()
					.filter(detail -> detail.getCatalog_id()
							.equalsIgnoreCase(orderItem.getItemVo().getCatalogId()))
					.findAny().orElse(null);

			if (null == sqliveOrderDetail) {
				
				SqTradingMqService.updateLiveOrder(false, orderId);
				
				return false;
			}
		}

		SqTradingMqService.updateLiveOrder(true, orderId);
		
		return true;
	}
	
	/**
	 * 
	 * @throws Exception
	 */
	public void verify() throws Exception {

		Logger.verifyEquals(ECode.SUCCESS, placeorderCall.getString("code"),
				"验证code");

		Logger.verifyEquals("0", placeorderCall.getString("bcode"), "验证bcode");

		PlaceOrderResp orderResp = placeorderCall.getPlaceOrderResp();

		Logger.verifyEquals(true, orderResp.getSuccess(), "验证success");

		if (!orderResp.getSuccess()) {

			Logger.fail(new RuntimeException("!!!!!!!!!下单失败！"));
		}

		long mainOrderId = orderResp.getMainOrderId();

		// 校验主单表(main_order)
		verifyMainOrderDb(mainOrderId, placeOrderReq.getProxyOrderId(), placeOrderReq.getPayDeductAmount(), placeOrderReq.getIntegral());

		List<Long> orderIds = orderResp.getOrderIds();

		MainOrder mainOrder = buildOrder();

		List<Order> orders = new ArrayList<Order>();

		for (OrderGroup orderGroup : mainOrder.getOrderGroups())
			orderGroup.getOrders().forEach(temp -> orders.add(temp));
		
		Long sellerId = 0L;

		for (int i = 0; i < orderIds.size(); i++) {

			long orderId = orderIds.get(i);

			Order expectedOrder = orders.get(i);
			
			Boolean isLiveOrder = isLiveOrder(expectedOrder.getOrderItems(),
					orderId);

			OrderPo actualOrder = orderShardingWapper
					.selectOrderbyOrderId(orderIds.get(i));

			// 校验订单表(order)
			verifyOrderDb(expectedOrder, actualOrder);
			
			// 直播订单校验
			Logger.verifyEquals(isLiveOrder,
					Utils.falseIfNull(actualOrder.getLiveOrder()),
					"验证数据库LiveOrder");

			// 校验订单扩展表(order_ext)
			verifyOrderExtDb(expectedOrder, orderId);

			List<OrderItem> expectedOrderDetails = expectedOrder
					.getOrderItems();

			List<OrderDetailPo> actualOrderDetails = orderShardingWapper
					.selectOrderDetailbyOrderId(orderId);

			BigDecimal orderTotalPrice = actualOrderDetails
					.stream()
					.map(detail -> detail.getProductPrice().multiply(
							new BigDecimal(detail.getProductCount())))
					.reduce(BigDecimal.ZERO, BigDecimal::add);

			BigDecimal orderFreight = actualOrderDetails
					.stream()
					.filter(detail -> !Utils.falseIfNull(detail
							.getFullReductionFreeFreight()))
					.map(detail -> detail.getFreight())
					.reduce(BigDecimal.ZERO, BigDecimal::add);

			BigDecimal orderYmtCouponAmount = actualOrderDetails.stream()
					.map(detail -> detail.getYmtCouponAmount())
					.reduce(BigDecimal.ZERO, BigDecimal::add);

			BigDecimal orderSellerCouponAmount = actualOrderDetails.stream()
					.map(detail -> detail.getSellerCouponAmount())
					.reduce(BigDecimal.ZERO, BigDecimal::add);

			BigDecimal orderServiceAmount = actualOrderDetails.stream()
					.map(detail -> detail.getServiceAmount())
					.reduce(BigDecimal.ZERO, BigDecimal::add);
			
			BigDecimal payableAmount = actualOrderDetails.stream()
					.map(detail -> detail.getPayableAmount())
					.reduce(BigDecimal.ZERO, BigDecimal::add);
			
			BigDecimal orderRegionDiscountAmount = actualOrderDetails.stream()
					.map(detail -> detail.getRegionDiscountAmount())
					.reduce(BigDecimal.ZERO, BigDecimal::add);
			
			if (isCDFMember(actualOrder.getSellerId())) {
				
				Long orderIntegral = actualOrderDetails.stream()
						.filter(detail -> null != detail.getIntegral())
						.mapToLong(OrderDetailPo::getIntegral).sum();
				
				DataUtil.verifyDecimalEquals(actualOrder.getIntegral(),
						orderIntegral, "验证数据库订单上的orderIntegral为该订单所有商品总积分之和");
			}
			
			// 计算订单的taxFee
			BigDecimal taxFee = calActualOrderTaxFee(actualOrderDetails);

			DataUtil.verifyDecimalEquals(actualOrder.getTotalPrice(),
					orderTotalPrice, "验证数据库订单上的TotalPrice为该订单所有商品总价之和");

			DataUtil.verifyDecimalEquals(actualOrder.getFreight(),
					orderFreight, "验证数据库订单上的Freight为该订单所有商品运费之和");

			DataUtil.verifyDecimalEquals(actualOrder.getYmtCouponAmount(),
					orderYmtCouponAmount,
					"验证数据库订单上的总YmatouCouponValue为该订单所有商品平台券之和");

			DataUtil.verifyDecimalEquals(actualOrder.getSellerCouponAmount(),
					orderSellerCouponAmount,
					"验证数据库订单上的总orderSellerCouponAmount为该订单所有商品商家券之和");

			DataUtil.verifyDecimalEquals(taxFee, actualOrder.getTaxFee(),
					"验证数据库订单上的总TaxFee为该订单所有商品税费之和");

			DataUtil.verifyDecimalEquals(orderServiceAmount,
					actualOrder.getServiceAmount(),
					"验证数据库订单上的总serviceAmount为该订单所有商品服务费之和");
			
			DataUtil.verifyDecimalEquals(orderServiceAmount,
					actualOrder.getServiceAmount(),
					"验证数据库订单上的总serviceAmount为该订单所有商品服务费之和");
			
			DataUtil.verifyDecimalEquals(payableAmount,
					actualOrder.getPayableAmount(),
					"验证数据库订单上的总payableAmount为该订单所有商品服务费之和");
			
			DataUtil.verifyDecimalEquals(orderRegionDiscountAmount,
					actualOrder.getRegionDiscountAmount(),
					"验证数据库订单上的总RegionDiscountAmount为该订单所有商品服务费之和");

			if (placeOrderReq.getBizSource() != null) {

				BizVo expectedBiz = placeOrderReq.getBizSource();

				OrderBizPo actualOrderBiz = orderShardingWapper
						.selectOrderBizbyOrderId(orderId);

				// 校验订单业务来源表order_biz
				verifyOrderBizDb(expectedBiz, actualOrderBiz);
			}

			// 校验order_biz_log
			verifyOrderBizLogDb(orderId, placeOrderReq.getShenqiBuyOrderCsId());

			// 校验订单商品表(order_detail)
			verifyOrderDetailDb(expectedOrderDetails, actualOrderDetails,
					expectedOrder, actualOrder.getGoodsOwnerId());

			// 校验利润
			this.verifyShenqiSellerProfit(actualOrder, actualOrderDetails, expectedOrder.getIsInherited(),
					expectedOrderDetails.get(0).getShenqiProxyChain());

			if (placeOrderReq.getTravelerVos() != null
					&& placeOrderReq.getTravelerVos().size() != 0) {

				this.verifyOrderTraveler(placeOrderReq.getTravelerVos(),
						orderId, actualOrder.getUserId(),
						actualOrder.getSellerId());
			}
			
			sellerId = actualOrder.getOrderId();
		}
		
		if (isCDFMember(sellerId)) {
			
			List<OrderPo> actualOrders = orderShardingWapper.selectOrderbyMainOrderId(mainOrderId);
			
			Long orderIntegral = actualOrders.stream()
					.filter(detail -> null != detail.getIntegral())
					.mapToLong(OrderPo::getIntegral).sum();
			
			DataUtil.verifyDecimalEquals(placeOrderReq.getIntegral(),
					orderIntegral, "验证数据库订单上的orderIntegral为该订单所有总积分之和");
		}
	}

	public void verifyOrderBizLogDb(long orderId, Long shenqiBuyOrderCsId) {

		if (shenqiBuyOrderCsId != null) {

			Logger.comment("验证OrderBizLog表");

			OrderBizLogPo actualOrderBizLogPo = orderShardingWapper
					.selectOrderBizLogByOrderId(orderId);

			Logger.verifyEquals("SHENQI_CS_BUY_ORDER",
					actualOrderBizLogPo.getBizType(), "验证BizType");
			Logger.verifyEquals(
					String.format("购买订单客服Id：%s",
							placeOrderReq.getShenqiBuyOrderCsId()),
					actualOrderBizLogPo.getContent(), "验证content");
		}
	}

	/**
	 * 校验主单表(main_order)
	 * 
	 * @param mainOrderId
	 */
	public void verifyMainOrderDb(long mainOrderId, long proxyOrderId, BigDecimal payDeductAmount, Long integral) {

		MainOrderPo actualMainOrder = orderShardingWapper
				.selectMianOrderbyId(mainOrderId);

		Logger.comment(String.format("校验主单表(main_order) mainOrderId:%s",
				mainOrderId));

		Logger.verifyEquals(mainOrderId,
				actualMainOrder.getMainOrderId(), "验证数据库MainOrderId");

		Logger.verifyEquals(proxyOrderId,
				actualMainOrder.getProxyOrderId(), "验证数据库ProxyOrderId");

		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualMainOrder.getAddTime()) < 2,
				"验证数据库AddTime跟系统当前时间差为2分钟内");

		DataUtil.verifyDecimalEquals(payDeductAmount,
				actualMainOrder.getPayDeductAmount(), "验证数据库pay_deduct_amount");

		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualMainOrder.getUpdateTime()) < 2,
				"验证数据库UpdateTime跟系统当前时间差为2分钟内");
		
		DataUtil.verifyDecimalEquals(integral,
				actualMainOrder.getIntegral(), "验证数据库Integral");
	}

	/**
	 * 校验订单表(order)
	 * 
	 * @param expectedOrder
	 * @param actualOrder
	 */
	private void verifyOrderDb(Order expectedOrder, OrderPo actualOrder) {

		Logger.comment(String.format("校验订单表(order) orderId:%s",
				actualOrder.getOrderId()));
		
		List<OrderItemVo> orderItems = expectedOrder.getOrderVo().getOrderItems();

		Logger.verifyEquals(placeOrderReq.getMainOrderId(),
				actualOrder.getMainOrderId(), "验证数据库MainOrderId");

		Logger.verifyEquals(expectedOrder.getSellerId(),
				actualOrder.getSellerId(), "验证数据库SellerId");
		DataUtil.verifyDecimalEquals(expectedOrder.getFreight(),
				actualOrder.getFreight(), "验证数据库Freight");

		DataUtil.verifyDecimalEquals(expectedOrder.getOrderVo()
				.getEarnestCardAmount(), actualOrder.getEarnestCardAmount(),
				"验证数据库EarnestCardAmount");
		DataUtil.verifyDateEquals(expectedOrder.getOrderVo()
				.getPaymentStartTime(), actualOrder.getPaymentStartTime(),
				"验证数据库PaymentStartTime");
		DataUtil.verifyDateEquals(expectedOrder.getOrderVo()
				.getPaymentEndTime(), actualOrder.getPaymentEndTime(),
				"验证数据库PaymentEndTime");
		Logger.verifyEquals(false, actualOrder.getCanConfirm(),
				"验证数据库CanConfirm");
		DataUtil.verifyDecimalEquals(expectedOrder.getTaxFee(),
				actualOrder.getTaxFee(), "验证数据库TaxFee");
		//不用积分的支付金额
		BigDecimal excludeIntegralPayableAmount = actualOrder
				.getTotalPrice()
				.add(Utils.zeroIfNull(actualOrder.getFreight()))
				.add(Utils.zeroIfNull(actualOrder.getOrderDiscount()))
				//税费
				.add(Utils.zeroIfNull(actualOrder.getTaxFee()))
				//服务费
				.add(Utils.zeroIfNull(actualOrder.getServiceAmount()))
				//0
				.subtract(Utils.zeroIfNull(actualOrder.getYmtCouponAmount()))
				//优惠券
				.subtract(Utils.zeroIfNull(actualOrder.getSellerCouponAmount()))
				//满减
				.subtract(Utils.zeroIfNull(actualOrder.getPromotionAmount()))
				//平台满减？
				.subtract(Utils.zeroIfNull(actualOrder.getYmtPromotionAmount()))
				//区域折扣 比如香港地址有折扣
				.subtract(Utils.zeroIfNull(actualOrder.getRegionDiscountAmount()));
		//用积分的金额excludeIntegralPayableAmount-积分换算金额
		BigDecimal payableAmount = excludeIntegralPayableAmount.subtract(Utils
				.zeroIfNull(actualOrder.getIntegralDeductionAmount()));
		
		DataUtil.verifyDecimalEquals(
				payableAmount, actualOrder
						.getPayableAmount(), "验证数据库PayableAmount");

		Logger.verifyEquals(expectedOrder.getOrderVo().getLogisticsType()
				.getCode(), actualOrder.getLogisticsType(),
				"验证数据库LogisticsType");
		
		if (payableAmount.compareTo(BigDecimal.ZERO) == 0) {

			Logger.verifyEquals(2, actualOrder.getOrderStatus(),
					"验证数据库OrderStatus");
			Logger.verifyNotNull(actualOrder.getPaymentId(), "验证数据库PaymentId");
			Logger.verifyNotNull(actualOrder.getPaidTime(), "验证数据库PaidTime");
		} else {
			
			Logger.verifyEquals(1, actualOrder.getOrderStatus(),
					"验证数据库OrderStatus");
			Logger.verifyEquals(null, actualOrder.getPaymentId(), "验证数据库PaymentId");
			Logger.verifyEquals(null, actualOrder.getPaidTime(), "验证数据库PaidTime");
		}
		
		DataUtil.verifyDecimalEquals(expectedOrder.getTotalProductPrice(),
				actualOrder.getTotalPrice(), "验证数据库TotalPrice");

		DataUtil.verifyDecimalEquals(expectedOrder.getOrderDiscount(),
				actualOrder.getOrderDiscount(), "验证数据库OrderDiscount");

		Logger.verifyEquals(expectedOrder.getYmatouCouponCode(),
				actualOrder.getYmtCouponCode(), "验证数据库YmtCouponCode");

		DataUtil.verifyDecimalEquals(expectedOrder.getYmatouCouponValue(),
				actualOrder.getYmtCouponAmount(), "验证数据库YmtCouponAmount");

		DataUtil.verifyDecimalEquals(expectedOrder.getSellerPromotionAmount(),
				actualOrder.getPromotionAmount(), "验证数据库PromotionAmount");

		Logger.verifyEquals(expectedOrder.getSellerCouponCode(),
				actualOrder.getSellerCouponCode(), "验证数据库SellerCouponCode");
		
		DataUtil.verifyDecimalEquals(expectedOrder.getSellerCouponValue(),
				actualOrder.getSellerCouponAmount(),
				"验证数据库SellerCouponAmount");
		
		if (null == expectedOrder.getOrderCouponDetailList())
			Logger.comment("该订单没有使用优惠券");
		else
			this.verifyOrderCouponDetail(expectedOrder.getOrderCouponDetailList(),
					actualOrder.getOrderId(), placeOrderReq.getMainOrderId());
		
		DataUtil.verifyDecimalEquals(BigDecimal.ZERO,
				actualOrder.getAccountPaidAmount(), "验证数据库AccountPaidAmount");
		DataUtil.verifyDecimalEquals(BigDecimal.ZERO,
				actualOrder.getThirdpartyPaidAmount(),
				"验证数据库ThirdpartyPaidAmount");

		DataUtil.verifyDecimalEquals(expectedOrder.getCardAmount(),
				actualOrder.getCardAmount(), "验证数据库cardAmount");

		Logger.verifyEquals(Utils.zeroIfNull(placeOrderReq.getAddressId()),
				actualOrder.getAddressId(), "验证数据库AddressId");
		
		Logger.verifyEquals(null, actualOrder.getAcceptTime(),
				"验证数据库AcceptTime");
		Logger.verifyEquals(null, actualOrder.getDeliveryTime(),
				"验证数据库DeliveryTime");
		Logger.verifyEquals(null, actualOrder.getReceiveTime(),
				"验证数据库ReceiveTime");
		Logger.verifyEquals(null, actualOrder.getCancelTime(),
				"验证数据库CancelTime");

		Logger.verifyEquals(false, actualOrder.getXloboDelivery(),
				"验证数据库XloboDelivery");
		Logger.verifyEquals(expectedOrder.containsPreSalePrds(),
				actualOrder.getPresale(), "验证数据库Presale");

		Logger.verifyEquals(RiskControlStatusEnum.Unknown.getCode(),
				actualOrder.getRiskStatus(), "验证数据库RiskStatus");

		Logger.verifyEquals(0, actualOrder.getOrderStatusMemo(),
				"验证数据库orderStatusMemo");

		Logger.verifyEquals(false, actualOrder.getLocked(), "验证数据库Locked");
		Logger.verifyEquals(false, actualOrder.getDeleted(), "验证数据库Deleted");

		Logger.verifyEquals(null, actualOrder.getCancelReason(),
				"验证数据库CancelReason");

		Logger.info("时间差为 :" + Utils.calcTimeSpanMin(actualOrder.getAddTime()));
		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualOrder.getAddTime()) < 2,
				"验证数据库AddTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualOrder.getAddTime()) < 2,
				"验证数据库UpdateTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(expectedOrder.getSellerCouponCode(),
				actualOrder.getSellerCouponCode(), "验证数据库SellerCouponCode");
		Logger.verifyEquals(0, actualOrder.getOrderStatusMemo(),
				"验证数据库OrderStatusMemo");

		Logger.verifyEquals(placeOrderReq.getUserId(), actualOrder.getUserId(),
				"验证数据库UserId");
		DataUtil.verifyDecimalEquals(BigDecimal.ZERO,
				actualOrder.getThirdpartyDiscount(), "验证数据库ThirdpartyDiscount");
		DataUtil.verifyDecimalEquals(expectedOrder.getOrderVo()
				.getAutoCancelOrderHours(), actualOrder.getAutoCancelHour(),
				"验证数据库AutoCancelHour");
		Logger.verifyEquals(false, actualOrder.getDomesticDelivery(),
				"验证数据库DomesticDelivery");

		Logger.verifyEquals(null, actualOrder.getNewCustomer(),
				"验证数据库NewCustomer");
		Logger.verifyEquals(null, actualOrder.getNewSeller(), "验证数据库NewSeller");

		Logger.verifyEquals(expectedOrder.getOrderVo().isEcommerceFlag(),
				actualOrder.getPredictEcommerce(), "验证数据库PredictEcommerce");

		Logger.verifyEquals(null, actualOrder.getActualEcommerce(),
				"验证数据库ActualEcommerce");

		Logger.verifyEquals(expectedOrder.getGoodsOwnerId(),
				actualOrder.getGoodsOwnerId(), "验证数据库GoodsOwnerId");

		Logger.verifyEquals(placeOrderReq.getSalesman(),
				actualOrder.getSalesman(), "验证数据库Salesman");

		Logger.verifyEquals(expectedOrder.getShenqiLogisticsType(),
				actualOrder.getShenqiLogisticsType(),
				"验证数据库ShenqiLogisticsType");
		Logger.verifyEquals(expectedOrder.getCurrency(),
				actualOrder.getCurrency(), "验证数据库currency");
		Logger.verifyEquals(expectedOrder.getCurrencySymbol(),
				actualOrder.getCurrencySymbol(), "验证数据库currencySymbol");
		Logger.verifyEquals(
				expectedOrder.getOrderVo().getPackageDeliveryType(),
				actualOrder.getPackageDeliveryType(),
				"验证数据库packageDeliveryType");

		Logger.verifyEquals(placeOrderReq.getSupportOfflinePay(),
				actualOrder.getSupportOfflinePay(), "验证数据库supportOfflinePay");

		Logger.verifyEquals(
				Utils.falseIfNull(placeOrderReq.getShenqiProxyBuyOrder()),
				actualOrder.getShenqiProxyBuyOrder(),
				"验证数据库ShenqiProxyBuyorder");

		Logger.verifyEquals(placeOrderReq.getCustomSettlementCurrencyType(),
				actualOrder.getCustomSettlementCurrencyType(),
				"验证数据库CustomSettlementCurrencyType");

		Logger.verifyEquals(expectedOrder.getOrderVo().getOrderAlias(),
				actualOrder.getOrderAlias(), "验证数据库OrderAlias");

		Logger.verifyEquals(placeOrderReq.getPayChannelType(),
				actualOrder.getPayChannelType(), "验证数据库PayChannelType");

		Logger.verifyEquals(
				Utils.falseIfNull(placeOrderReq.getPickupInStores()),
				actualOrder.getPickupInStores(), "验证数据库PickupInStores");

		Logger.verifyEquals(expectedOrder.getShenqiIdCardRequirement(),
				actualOrder.getShenqiIdcardRequirement(),
				"验证数据库ShenqiIdcardRequirement");

		Logger.verifyEquals(
				Utils.falseIfNull(placeOrderReq.getPickupInStores()) == true ? false
						: expectedOrder.getShenqiIdCardRequirement() > 0,
				actualOrder.getNeedUploadIdcard(), "验证数据库NeedUploadIdcard");

		Logger.verifyEquals(expectedOrder.getOrderVo().getPurchaserIdcardId(),
				actualOrder.getPurchaserIdcardId(), "验证数据库PurchaserIdcardId");

		if (Utils.zeroIfNull(expectedOrder.getOrderVo().getPurchaserIdcardId()) > 0
				&& Utils.zeroIfNull(expectedOrder.getOrderVo()
						.getShenqiIdCardRequirement()) == 1)
			Logger.verifyEquals(true, actualOrder.getUploadedIdcard(),
					"验证数据库UploadedIdcard");

		Logger.verifyEquals(expectedOrder.getOrderVo().getWarehouseId(),
				actualOrder.getWarehouseId(), "验证数据库WarehouseId");

		Integer totalVStockCount = orderItems
				.stream()
				.mapToInt(
						orderItemVo -> Utils.zeroIfNull(orderItemVo
								.getVirtualProductNum())).sum();

		Logger.verifyEquals(totalVStockCount > 0 ? true : false,
				Utils.falseIfNull(actualOrder.getWaitInStock()),
				"验证数据库WaitInStock");
		Logger.verifyEquals(null, actualOrder.getInStockTime(),
				"验证数据库InStockTime");

		// 特殊情况，如果订单被风控且是线下支付的订单RiskOrder为true，一个主单所有子单都为true
		// 风控规则商品单价为20000，3个商品，总价60000
		if (actualOrder.getPayableAmount()
				.compareTo(new BigDecimal("60000.00")) == 0
				&& Utils.falseIfNull(actualOrder.getSupportOfflinePay()))
			Logger.verifyEquals(true, actualOrder.getPlaceRisk(),
					"验证数据库PlaceRisk");
		else
			Logger.verifyEquals(false, actualOrder.getPlaceRisk(),
					"验证数据库PlaceRisk");

		Logger.verifyEquals(expectedOrder.getAfterAcctivityFinishAccept(),
				actualOrder.getAfterActivityFinishAccept(),
				"验证数据库AfterActivityFinishAccept");
		
		if (isCDFMember(actualOrder.getSellerId())
				&& null != placeOrderReq.getIntegral()) {

			if (null == placeOrderReq.getIntegralExchangeRate()) {

				DataUtil.verifyDecimalEquals(
						new BigDecimal(actualOrder.getIntegral()),
						actualOrder.getIntegralDeductionAmount(),
						"验证数据库IntegralDeductionAmount");
			} else {

				DataUtil.verifyDecimalEquals(
						new BigDecimal(actualOrder.getIntegral()).multiply(
								placeOrderReq.getIntegralExchangeRate())
								.setScale(2, BigDecimal.ROUND_HALF_DOWN),
						actualOrder.getIntegralDeductionAmount(),
						"验证数据库IntegralDeductionAmount");
			}
			
			Logger.verifyEquals(actualOrder.getIntegral() >= 0, true,
					"验证数据库Integral");
		} else {

			DataUtil.verifyDecimalEquals(
					expectedOrder.getOrderIntegralDeduction(),
					actualOrder.getIntegralDeductionAmount(),
					"验证数据库IntegralDeductionAmount");
			Logger.verifyEquals(expectedOrder.getOrderIntegral(),
					actualOrder.getIntegral(), "验证数据库Integral");
		}
		
		Logger.verifyEquals(placeOrderReq.getIntegralServiceType(),
				actualOrder.getIntegralServiceType(),
				"验证数据库IntegralServiceType");
		
		DataUtil.verifyDecimalEquals(expectedOrder.getRegionDiscountValue(),
				actualOrder.getRegionDiscountAmount(),
				"验证数据库RegionDiscountAmount");
		DataUtil.verifyDecimalEquals(expectedOrder.getOrderVo().getRegionDiscountRatio(),
				actualOrder.getRegionDiscountRatio(), "验证数据库RegionDiscountRatio");
		
		Logger.verifyEquals(
				Utils.zeroIfNull(expectedOrder.getSellerCouponSource()),
				actualOrder.getSellerCouponSource(), "验证数据库SellerCouponSource");
		Logger.verifyEquals(
				Utils.zeroIfNull(expectedOrder.getSellerCouponType()),
				actualOrder.getSellerCouponType(), "验证数据库SellerCouponType");
		
		if (expectedOrder.getOrderVo().getCrossBorderType() == null) {

			// 跨境订单类型
			Integer crossBorderType = null;

			if (expectedOrder
					.getOrderItems()
					.stream()
					.allMatch(
							item -> Utils.falseIfNull(item.getItemVo()
									.getDomesticProduct())) == true)
				crossBorderType = 2;
			else if (expectedOrder
					.getOrderItems()
					.stream()
					.anyMatch(
							item -> Utils.falseIfNull(item.getItemVo()
									.getDomesticProduct())) == true)
				crossBorderType = 3;
			else
				crossBorderType = 1;

			Logger.verifyEquals(crossBorderType,
					actualOrder.getCrossBorderType(), "验证数据库CrossBorderType");

		} else {

			Logger.verifyEquals(
					expectedOrder.getOrderVo().getCrossBorderType(),
					actualOrder.getCrossBorderType(), "验证数据库CrossBorderType");
		}
		
		if (placeOrderReq.getGuideOrder())
			Logger.verifyEquals(true,
					(actualOrder.getOrderFlags() & 1 << 0) > 0,
					"验证GuideOrder为true");
		else
			Logger.verifyEquals(false,
					(actualOrder.getOrderFlags() & 1 << 0) > 0,
					"验证GuideOrder为false");

		if (expectedOrder.getCouponMainType() == 1)
			Logger.verifyEquals(true,
					(actualOrder.getOrderFlags() & 1 << 1) > 0,
					"验证CouponMainType为true");
		else
			Logger.verifyEquals(false,
					(actualOrder.getOrderFlags() & 1 << 1) > 0,
					"验证CouponMainType为false");

		if (expectedOrder.getIsPlatformSupplierOrder())
			Logger.verifyEquals(true,
					(actualOrder.getOrderFlags() & 1 << 2) > 0,
					"验证验证PlatformSupplierOrder为true");
		else
			Logger.verifyEquals(false,
					(actualOrder.getOrderFlags() & 1 << 2) > 0,
					"验证PlatformSupplierOrder为false");

		DataUtil.verifyDecimalEquals(placeOrderReq.getIntegralExchangeRate(),
				new BigDecimal(
						actualOrder.getIntegralExchangeRate() == null ? "0.00"
								: actualOrder.getIntegralExchangeRate()),
				"验证数据库IntegralExchangeRate");
	}

	/**
	 * 校验订单扩展表(order_ext)
	 * 
	 * @param actualOrder
	 * @param orderId
	 * @throws Exception
	 */
	private void verifyOrderExtDb(Order actualOrder, long orderId)
			throws Exception {

		// 等待下单回调处理完成
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		String phoneKey = "123456789";
		String addreeKey = "123456789";

		Logger.comment(String.format("校验订单扩展表(order_ext) orderId:%s", orderId));

		OrderExtPo actualOrderExt = orderWapper
				.selectOrderExtByOrderId(orderId);
		
		int n = 0;
		
		while (actualOrderExt == null) {
			
			n = n + 1;
			
			actualOrderExt = orderWapper
					.selectOrderExtByOrderId(orderId);
			
			if (n == 4) {
				
				Logger.comment("#############Thread.sleep(5000) 下单回调还没处理完");
				Logger.fail(new Exception("Thread.sleep(5000) 下单回调还没处理完"));
				return;
			}
			
			Thread.sleep(1000 * n);
		}

		if (placeOrderReq.getAddress() == null
				|| placeOrderReq.getAddress().equalsIgnoreCase(""))

			Logger.verifyEquals(placeOrderReq.getAddress(),
					actualOrderExt.getUserAddress(), "验证数据库userAddress");
		else {
			Logger.verifyEquals(CipherUtil.encryptAES(addreeKey,
					placeOrderReq.getAddress()), actualOrderExt
					.getUserAddress(), "验证数据库userAddress");
			Logger.verifyEquals(placeOrderReq.getAddress(),
					Utils.decryptAES(actualOrderExt.getUserAddress()),
					"验证数据库userAddress解密后的数据");
		}

		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualOrderExt.getAddTime()) < 2,
				"验证数据库AddTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualOrderExt.getUpdateTime()) < 2,
				"验证数据库UpdateTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(orderId, actualOrderExt.getOrderId(),
				"验证数据库OrderId");

		Long sellerId = actualOrder.getSellerId();
		Logger.verifyEquals(sellerId, actualOrderExt.getSellerId(),
				"验证数据库SellerId");

		DGUserInfo dgUserInfo = new DGUserWapper().selectDGUserInfo(
				sellerId.intValue()).get(0);

		Logger.verifyEquals(dgUserInfo.getLoginId(),
				actualOrderExt.getSellerLoginId(), "验证数据库SellerLoginId");

		Long userId = placeOrderReq.getUserId();

		Logger.verifyEquals(userId, actualOrderExt.getUserId(), "验证数据库UserId");

		Logger.verifyEquals(null, actualOrderExt.getUserLoginId(),
				"验证数据库UserLoginId");

		Logger.verifyEquals(placeOrderReq.getDeviceId(),
				actualOrderExt.getDeviceId(), "验证数据库DeviceId");
		Logger.verifyEquals(placeOrderReq.getSourceIp(),
				actualOrderExt.getSourceIp(), "验证数据库SourceIp");
		Logger.verifyEquals(placeOrderReq.getEquipmentId(),
				actualOrderExt.getEquipmentId(), "验证数据库EquipmentId");
		Logger.verifyEquals(placeOrderReq.getPostCode(),
				actualOrderExt.getPostCode(), "验证数据库PostCode");

		Logger.verifyEquals(null, actualOrderExt.getSellerNote(),
				"验证数据库SellerNote");
		Logger.verifyEquals(actualOrder.getOrderVo().getLeaveWord(),
				actualOrderExt.getLeaveWord(), "验证数据库LeaveWord");
		Logger.verifyEquals(placeOrderReq.getOrderSource().name(),
				actualOrderExt.getSourcePlatform(), "验证数据库SourcePlatform");

		Logger.verifyEquals(placeOrderReq.getAppTerminalSource().name(),
				actualOrderExt.getSourceTerminal(), "验证数据库SourceTerminal");

		Logger.verifyEquals(placeOrderReq.getTerminalSource().name(),
				actualOrderExt.getOperatingSystem(), "验证数据库OperatingSystem");

		Logger.verifyEquals(null, actualOrderExt.getSellerNoteLevel(),
				"验证数据库SellerNoteLevel");

		// 如果下单有出行人信息，则将第一个出行人的电话、名称写入数据库
		if (placeOrderReq.getTravelerVos() != null
				&& placeOrderReq.getTravelerVos().size() != 0) {

			TravelerVo travelerVo = placeOrderReq.getTravelerVos().get(0);

			placeOrderReq.setRecvMobile(travelerVo.getTravelerPhone());
			placeOrderReq.setRecvName(travelerVo.getTravelerName());
		}

		if (placeOrderReq.getRecvMobile() == null
				|| placeOrderReq.getRecvMobile().equalsIgnoreCase(""))

			Logger.verifyEquals(placeOrderReq.getRecvMobile(),
					actualOrderExt.getUserPhone(), "验证数据库userPhone");
		else {
			Logger.verifyEquals(CipherUtil.encryptAES(phoneKey,
					Utils.trimAndLeft(placeOrderReq.getRecvMobile(), 20)),
					actualOrderExt.getUserPhone(), "验证数据库userPhone");

			Logger.verifyEquals(
					CipherUtil.decryptAES(phoneKey,
							actualOrderExt.getUserPhone()),
					Utils.trimAndLeft(placeOrderReq.getRecvMobile(), 20),
					"验证数据库userPhone解密后的数据");
		}

		Logger.verifyEquals(Utils.trimAndLeft(placeOrderReq.getRecvName(), 50),
				actualOrderExt.getReceiver(), "验证数据库Receiver");
		
		if (null != placeOrderReq.getPickInStoreVo() && placeOrderReq.getPickupInStores()) {
			
			PickInStoreVo pickInStoreVo = placeOrderReq.getPickInStoreVo();
			PickInStorePo actualPickInStorePo = orderShardingWapper
					.selectPickInStorebyOrderId(orderId).get(0);
			
			Logger.verifyEquals(pickInStoreVo.getPickupType().byteValue(),
					actualPickInStorePo.getPickupType(), "验证PickupType");
			Logger.verifyEquals(pickInStoreVo.getPickupUserName(),
					actualPickInStorePo.getPickupUserName(), "验证PickupUserName");
			Logger.verifyEquals(pickInStoreVo.getPickupUserPhone(),
					actualPickInStorePo.getPickupUserPhone(),
					"验证PickupUserPhone");
			DataUtil.verifyDateEquals(
					pickInStoreVo.getUserReserveTimeSpanStart(),
					actualPickInStorePo.getUserReserveTimeSpanStart(),
					"验证UserReserveTimeSpanStart");
			DataUtil.verifyDateEquals(
					pickInStoreVo.getUserReserveTimeSpanEnd(),
					actualPickInStorePo.getUserReserveTimeSpanEnd(),
					"验证UserReserveTimeSpanEnd");
			Logger.verifyEquals(pickInStoreVo.getPickupStoreId(),
					actualPickInStorePo.getPickupStoreId(), "验证PickupStoreId");
			Logger.verifyEquals((byte) 0,
					actualPickInStorePo.getPickupStatus(), "验证PickupStatus");
			Logger.verifyEquals((byte) 1, actualPickInStorePo.getDeleteFlag(),
					"验证DeleteFlag");
			
		}

		Logger.verifyEquals(placeOrderReq.getEntryIdType(),
				actualOrderExt.getEntryIdType(), "验证数据库EntryIdType");
		DataUtil.verifyDateEquals(placeOrderReq.getEntryTime(),
				actualOrderExt.getEntryTime(), "验证数据库EntryTime");
		Logger.verifyEquals(placeOrderReq.getEntryIdNo(),
				actualOrderExt.getEntryIdNo(), "验证数据库EntryIdNo");
		Logger.verifyEquals(Utils.emptyIfNull(placeOrderReq.getEntryPort()).length() > 100 ?
						placeOrderReq.getEntryPort().substring(0, 100) : placeOrderReq.getEntryPort(),
				actualOrderExt.getEntryPort(), "验证数据库EntryPort");
		Logger.verifyEquals(placeOrderReq.getTransportation(),
				actualOrderExt.getTransportation(), "验证数据库Transportation");
	}

	/**
	 * 校验订单业务来源表order_biz
	 * 
	 * @param expectedBiz
	 * @param actualOrderBiz
	 */
	public void verifyOrderBizDb(BizVo expectedBiz, OrderBizPo actualOrderBiz) {

		Logger.comment(String.format("校验订单业务来源表(order_biz) orderId:%s",
				actualOrderBiz.getOrderId()));

		Logger.verifyEquals(expectedBiz.getBizId(), actualOrderBiz.getBizNo(),
				"验证数据库bizNo");

		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualOrderBiz.getAddTime()) < 2,
				"验证数据库AddTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualOrderBiz.getUpdateTime()) < 2,
				"验证数据库UpdateTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(expectedBiz.getBizType(),
				actualOrderBiz.getBizType(), "验证数据库BizType");

		Logger.verifyEquals(Utils.zeroIfNull(expectedBiz.getBizSubType()),
				actualOrderBiz.getBizSubType(), "验证数据库BizSubType");

		Logger.verifyEquals(Utils.zeroIfNull(expectedBiz.getBizStatus()),
				actualOrderBiz.getBizStatus(), "验证数据库BizStatus");
	}

	/**
	 * 校验订单商品表(order_detail)
	 * 
	 * @param expectedOrderDetails
	 * @param actualOrderDetails
	 * @throws Exception
	 */
	private void verifyOrderDetailDb(List<OrderItem> expectedOrderDetails,
			List<OrderDetailPo> actualOrderDetails, Order expectedOrder, Long goodsOwnerId)
			throws Exception {

		for (int i = 0; i < expectedOrderDetails.size(); i++) {

			OrderItem expectedOrderDetail = expectedOrderDetails.get(i);

			OrderDetailPo actualOrderDetail = actualOrderDetails.get(i);

			String goodsOwnerCatalogId = null;

			Logger.comment(String.format(
					"校验订单商品表(order_detail) orderId:%s,OrderDetailId:%s",
					actualOrderDetail.getOrderId(),
					actualOrderDetail.getOrderDetailId()));

			DataUtil.verifyDecimalEquals(expectedOrderDetail.getItemVo()
					.getFreight(), actualOrderDetail.getFreight(),
					"验证数据库Freight");

			DataUtil.verifyDecimalEquals(expectedOrderDetail.getItemVo()
					.getBookingPromotionAmount(), actualOrderDetail
					.getBookingPromotionAmount(), "验证数据库BookingPromotionAmount");

			DataUtil.verifyDecimalEquals(expectedOrderDetail.getItemVo()
					.getEarnestAmount(), actualOrderDetail.getEarnestAmount(),
					"验证数据库EarnestAmount");

			Logger.verifyEquals(true,
					Utils.calcTimeSpanMin(actualOrderDetail.getAddTime()) < 2,
					"验证数据库AddTim跟系统当前时间差为2分钟内");

			DataUtil.verifyDecimalEquals(expectedOrderDetail.getItemVo()
					.getProductPrice(), actualOrderDetail.getProductPrice(),
					"验证数据库ProductPrice");

			DataUtil.verifyDecimalEquals(BigDecimal.ZERO,
					actualOrderDetail.getThirdpartyDiscount(),
					"验证数据库ThirdpartyDiscount");
			
//			if (TradingForDGSQCallService.isCDFCoupon(Utils
//					.zeroIfNull(expectedOrder.getSellerCouponSource()))) {
//
//				if (actualOrderDetail.getExchangeBuy())
//					DataUtil.verifyDecimalEquals(BigDecimal.ZERO,
//							actualOrderDetail.getSellerCouponAmount(),
//							"验证数据库SellerCouponAmount");
//				else
//					DataUtil.verifyDecimalEquals(1,
//							actualOrderDetail.getSellerCouponAmount()
//									.compareTo(BigDecimal.ZERO),
//							"验证数据库SellerCouponAmount");
//			} else {
//
//				DataUtil.verifyDecimalEquals(
//						expectedOrderDetail.getSellerCouponValue(),
//						actualOrderDetail.getSellerCouponAmount(),
//						"验证数据库SellerCouponAmount");
//			}
			
			DataUtil.verifyDecimalEquals(
					expectedOrderDetail.getSellerCouponValue(),
					actualOrderDetail.getSellerCouponAmount(),
					"验证数据库SellerCouponAmount");

			DataUtil.verifyDecimalEquals(
					expectedOrderDetail.getYmatouCouponValue(),
					actualOrderDetail.getYmtCouponAmount(),
					"验证数据库YmtCouponAmount");

			DataUtil.verifyDecimalEquals(expectedOrderDetail.getItemVo()
					.getYmtPromotionAmount(), actualOrderDetail
					.getYmtPromotionAmount(), "验证数据库ymt_promotion_amount");

			DataUtil.verifyDecimalEquals(
					expectedOrderDetail.getSellerPromotionAmount(),
					actualOrderDetail.getPromotionAmount(),
					"验证数据库PromotionAmount");

			Logger.verifyEquals(
					true,
					Utils.calcTimeSpanMin(actualOrderDetail.getUpdateTime()) < 2,
					"验证数据库UpdateTime跟系统当前时间差为2分钟内");

			Logger.verifyEquals(expectedOrderDetail.getItemVo().getProductId(),
					actualOrderDetail.getProductId(), "验证数据库ProductId");

			Logger.verifyEquals(expectedOrderDetail.getItemVo().getCatalogId(),
					actualOrderDetail.getCatalogId(), "验证数据库CatalogId");
			
			// 如果是兑换券，取speecc后的字符串
			if (Utils.zeroIfNull(expectedOrder.getSellerCouponType()) == 5
					&& actualOrderDetail.getCatalogId().startsWith("speecc"))
				goodsOwnerCatalogId = actualOrderDetail.getCatalogId()
						.substring(6);
			else
				goodsOwnerCatalogId = actualOrderDetail.getCatalogId();

			Logger.verifyEquals(expectedOrderDetail.getItemVo()
					.getStockStatus() == null ? 0 : expectedOrderDetail
					.getItemVo().getStockStatus().getCode(), actualOrderDetail
					.getCatalogType(), "验证数据库CatalogType");

			Logger.verifyEquals(
					expectedOrderDetail.getItemVo().getProductNum(),
					actualOrderDetail.getProductCount(), "验证数据库ProductCount");

			if (expectedOrderDetail.getItemVo().getBondedArea() != null) {
				Logger.verifyEquals(expectedOrderDetail.getItemVo()
						.getBondedArea().getCode(),
						actualOrderDetail.getBondedArea(), "验证数据库BondedArea");
			}

			Logger.verifyEquals(
					expectedOrderDetail.getItemVo().getProductVer(),
					actualOrderDetail.getProductSnap(), "验证数据库ProductSnap");

			Logger.verifyEquals(
					expectedOrderDetail.getItemVo().getPriceType() == null ? 0
							: expectedOrderDetail.getItemVo().getPriceType()
									.getCode(), actualOrderDetail
							.getPriceType(), "验证数据库PriceType");

			DataUtil.verifyDecimalEquals(expectedOrderDetail.getItemVo()
					.getOriginalPrice(), actualOrderDetail.getOriginalPrice(),
					"验证数据库OriginalPrice");

			DataUtil.verifyDecimalEquals(expectedOrderDetail.getDiscount(),
					actualOrderDetail.getDiscount(), "验证数据库Discount");

			long activityId = 0, activityTemplateId = 0, productInActivityId = 0;

			if (expectedOrderDetail.getItemVo().getActivity() != null) {

				activityId = expectedOrderDetail.getItemVo().getActivity()
						.getActivityId();

				activityTemplateId = expectedOrderDetail.getItemVo()
						.getActivity().getActivityTemplateId();

				productInActivityId = expectedOrderDetail.getItemVo()
						.getActivity().getProductInActivityId();
			}

			Logger.verifyEquals(activityId,
					Long.valueOf(actualOrderDetail.getActivityId()),
					"验证数据库ActivityId");

			Logger.verifyEquals(
					expectedOrderDetail.getItemVo().getTariffType(),
					actualOrderDetail.getTariffType(), "验证数据库TariffType");

			if (expectedOrderDetail.getItemVo().getProductRefundChannel() != null) {

				Logger.verifyEquals(expectedOrderDetail.getItemVo()
						.getProductRefundChannel().getCode(),
						actualOrderDetail.getRefundChannel(),
						"验证数据库RefundChannel");
			}

			if (expectedOrderDetail.getItemVo().getSalesType() != null) {

				Logger.verifyEquals(expectedOrderDetail.getItemVo()
						.getSalesType().getCode(),
						actualOrderDetail.getSalesType(), "验证数据库SalesType");
			}

			Logger.verifyEquals(
					expectedOrderDetail.getItemVo().isFreightFree(),
					actualOrderDetail.getFreeFreight(), "验证数据库FreeFreight");
			Logger.verifyEquals(expectedOrderDetail.getItemVo().isPspProduct(),
					actualOrderDetail.getPspProduct(), "验证数据库PspProduct");
			Logger.verifyEquals(expectedOrderDetail.getItemVo().isSubProduct(),
					actualOrderDetail.getSubProduct(), "验证数据库SubProduct");

			Logger.verifyEquals(expectedOrderDetail.getItemVo()
					.getFirstCategoryId(), Long.valueOf(actualOrderDetail
					.getFirstCategoryId()), "验证数据库FirstCategoryId");
			Logger.verifyEquals(expectedOrderDetail.getItemVo()
					.getSecondCategoryId(), Long.valueOf(actualOrderDetail
					.getSecondCategoryId()), "验证数据库SecondCategoryId");

			Logger.verifyEquals(expectedOrderDetail.getItemVo()
					.getThirdCategoryId(), Long.valueOf(actualOrderDetail
					.getThirdCategoryId()), "验证数据库ThirdCategoryId");

			Logger.verifyEquals(activityTemplateId,
					Long.valueOf(actualOrderDetail.getActivityTempId()),
					"验证数据库ActivityTempId");

			Logger.verifyEquals(productInActivityId,
					Long.valueOf(actualOrderDetail.getProductInActivityId()),
					"验证数据库ProductInActivityId");

			Logger.verifyEquals(expectedOrderDetail.getItemVo()
					.isSupportsRtnWithoutReason(), actualOrderDetail
					.getSupportNoReasonRefund(), "验证数据库SupportNoReasonRefund");

			if (expectedOrderDetail.getSellerPromotion() != null) {

				OrderDetailPromotionPo actualOrderDetailPromotion = orderShardingWapper
						.selectOrderDetailPromotionByOrderDetailId(actualOrderDetail
								.getOrderDetailId());

				// 校验订单营销表（order_detail_promotion）
				verifyOrderDetailPromotionDb(expectedOrderDetail,
						actualOrderDetailPromotion,
						actualOrderDetail.getOrderId());
			}

			boolean fullReductionFreeFreight = Utils
					.falseIfNull(actualOrderDetail
							.getFullReductionFreeFreight());

			int scale = 0;

			if (null == placeOrderReq.getCurrency())
				scale = 2;
			else if (null != placeOrderReq.getCurrency()
					&& placeOrderReq.getCurrency().equalsIgnoreCase("JPY"))
				scale = 0;
			else
				scale = 2;

			// 直销商没有代理价，有代理价的情况才会查询代理链
			if (null != actualOrderDetail.getProxyPrice()) {

				
				List<ShenqiProxyChainPo> expectedShenqiProxyChainPoList = expectedOrderDetail.getShenqiProxyChain();

				expectedShenqiProxyChainPoList
						.get(expectedShenqiProxyChainPoList.size() - 1)
						.setPictureUrl(
								expectedOrderDetail.getItemVo().getPictureUrl());
				expectedShenqiProxyChainPoList.get(
						expectedShenqiProxyChainPoList.size() - 1).setTitle(
						expectedOrderDetail.getItemVo().getProductName());

				Logger.verifyEquals(
						expectedShenqiProxyChainPoList.get(
								expectedShenqiProxyChainPoList.size() - 1)
								.getFromParentPrice(), actualOrderDetail
								.getProxyPrice(), "验证数据库ProxyPrice");

				this.verifyShenqiProxyChainDb(expectedShenqiProxyChainPoList,
						actualOrderDetail.getOrderId(),
						actualOrderDetail.getCatalogId());

				goodsOwnerCatalogId = expectedShenqiProxyChainPoList.get(0)
						.getProxyCatalogId();

				// 直销商才收服务费
				DataUtil.verifyDecimalEquals(null,
						actualOrderDetail.getServiceRate(), "验证数据库ServiceRate");
				DataUtil.verifyDecimalEquals(null,
						actualOrderDetail.getServiceAmount(),
						"验证数据库serviceAmount");
				
				DataUtil.verifyDecimalEquals(expectedShenqiProxyChainPoList
						.get(expectedShenqiProxyChainPoList.size() - 1)
						.getCostPrice(), actualOrderDetail.getPrimeCostPrice(),
						"验证数据库PrimeCostPrice");
			} else {

				BigDecimal serviceRate = expectedOrderDetail.getServiceRate();
				BigDecimal serviceAmount = SqTradingCallService
						.getServiceAmount(actualOrderDetail);

				// 直销订单验证服务费
				DataUtil.verifyDecimalEquals(Utils.zeroIfNull(serviceRate),
						actualOrderDetail.getServiceRate(), "验证数据库ServiceRate");
				DataUtil.verifyDecimalEquals(
						serviceAmount.setScale(scale, BigDecimal.ROUND_HALF_UP),
						actualOrderDetail.getServiceAmount(),
						"验证数据库serviceAmount");
				
				DataUtil.verifyDecimalEquals(expectedOrderDetail.getItemVo()
						.getPrimeCostPrice(),
						actualOrderDetail.getPrimeCostPrice(),
						"验证数据库PrimeCostPrice");
				
				// 如果是一品多码商户且该商品不是组合商品，校验一品多码表
				if (goodsOwnerId == multiCDFCodeGoodsOwnerId
						&& !expectedOrderDetail.getItemVo().isSubProduct())
					this.verifyOrderDetailSubCodeDb(actualOrderDetail
							.getOrderId(), expectedOrderDetail.getItemVo()
							.getCatalogId(), expectedOrderDetail.getItemVo()
							.getProductNum());
			}

			DataUtil.verifyDecimalEquals(Utils.zeroIfNull(expectedOrderDetail
					.getItemVo().getProdTaxRate()), actualOrderDetail
					.getTaxRate(), "验证数据库TaxRate");

			BigDecimal taxFee = Utils
					.zeroIfNull(
							fullReductionFreeFreight ? BigDecimal.ZERO
									: actualOrderDetail.getFreight())
					.divide(new BigDecimal(actualOrderDetail.getProductCount()),
							2, BigDecimal.ROUND_UP)
					.add(actualOrderDetail.getProductPrice())
					.add(Utils.zeroIfNull(actualOrderDetail.getDiscount())
							.divide(new BigDecimal(actualOrderDetail
									.getProductCount()), 2, BigDecimal.ROUND_UP))
					.subtract(
							Utils.zeroIfNull(actualOrderDetail
									.getYmtCouponAmount()))
					.subtract(
							Utils.zeroIfNull(actualOrderDetail
									.getYmtPromotionAmount()))
					.subtract(
							Utils.zeroIfNull(
									actualOrderDetail.getSellerCouponAmount())
									.divide(new BigDecimal(actualOrderDetail
											.getProductCount()), 2,
											BigDecimal.ROUND_UP))
					.subtract(
							Utils.zeroIfNull(
									actualOrderDetail.getPromotionAmount())
									.divide(new BigDecimal(actualOrderDetail
											.getProductCount()), 2,
											BigDecimal.ROUND_UP))
					.subtract(
							Utils.zeroIfNull(
									actualOrderDetail.getRegionDiscountAmount())
									.divide(new BigDecimal(actualOrderDetail
											.getProductCount()), 2,
											BigDecimal.ROUND_UP))
					.multiply(actualOrderDetail.getTaxRate())
					.setScale(scale, BigDecimal.ROUND_HALF_UP);

			if (SqTradingCallService.isFreePerimeters(placeOrderReq
					.getAddress()))
				DataUtil.verifyDecimalEquals(BigDecimal.ZERO,
						actualOrderDetail.getTaxFee(), "验证数据库TaxFee");
			else
				DataUtil.verifyDecimalEquals(taxFee,
						actualOrderDetail.getTaxFee(), "验证数据库TaxFee");

			Logger.verifyEquals(expectedOrderDetail.getItemVo()
					.isBuyDailyLimit(), actualOrderDetail.isDailyLimit(),
					"验证数据库DailyLimit");

			DataUtil.verifyDecimalEquals(expectedOrderDetail.getItemVo()
					.getVirtualProductNum(), Utils.zeroIfNull(actualOrderDetail
					.getvStockCount()), "验证数据库vStockCount");
			
			if (null == expectedOrder.getOrderVo().getCrossBorderType()) {
				Logger.verifyEquals(expectedOrderDetail.getItemVo()
						.getDomesticProduct(), actualOrderDetail
						.getDomesticProduct(), "验证数据库DomesticProduct");

			} else {

				if (Utils.zeroIfNull(expectedOrder.getOrderVo()
						.getCrossBorderType()) != 2)
					Logger.verifyEquals(false,
							actualOrderDetail.getDomesticProduct(),
							"验证数据库DomesticProduct");
				else
					Logger.verifyEquals(true,
							actualOrderDetail.getDomesticProduct(),
							"验证数据库DomesticProduct");
			}

			Logger.verifyEquals(Utils.zeroIfNull(actualOrderDetail
					.getvStockCount()) > 0 ? true : false, Utils
					.falseIfNull(actualOrderDetail.getWaitInStock()),
					"验证数据库WaitInStock");
			Logger.verifyEquals(goodsOwnerCatalogId,
					actualOrderDetail.getGoodsOwnerCatalogId(),
					"验证数据库GoodsOwnerCatalogId");
			Logger.verifyEquals(null, actualOrderDetail.getInStockTime(),
					"验证数据库InStockTime");
			
			if (isCDFMember(goodsOwnerId)
					&& null != placeOrderReq.getIntegral()) {
				
				if (null == placeOrderReq.getIntegralExchangeRate()) {
					
					DataUtil.verifyDecimalEquals(
							new BigDecimal(actualOrderDetail.getIntegral()),
							actualOrderDetail.getIntegralDeductionAmount(),
							"验证数据库IntegralDeductionAmount");
				} else {
					
					DataUtil.verifyDecimalEquals(
							new BigDecimal(actualOrderDetail.getIntegral())
									.multiply(
											placeOrderReq
													.getIntegralExchangeRate())
									.setScale(2, BigDecimal.ROUND_HALF_DOWN),
							actualOrderDetail.getIntegralDeductionAmount(),
							"验证数据库IntegralDeductionAmount");
				}
				
				Logger.verifyEquals(actualOrderDetail.getIntegral() >= 0, true,
						"验证数据库Integral");
			} else {

				DataUtil.verifyDecimalEquals(
						expectedOrderDetail.getIntegralDeduction(),
						actualOrderDetail.getIntegralDeductionAmount(),
						"验证数据库IntegralDeductionAmount");
				Logger.verifyEquals(expectedOrderDetail.getIntegral(),
						actualOrderDetail.getIntegral(), "验证数据库Integral");
			}
			
			Logger.verifyEquals(Utils.falseIfNull(expectedOrderDetail
					.getItemVo().getExchangeBuy()), actualOrderDetail
					.getExchangeBuy(), "验证数据库ExchangeBuy");
			Logger.verifyEquals(expectedOrderDetail
					.getItemVo().getExchangeBuyActivityId(), actualOrderDetail
					.getExchangeBuyActivityId(), "验证数据库ExchangeBuyActivityId");

			BigDecimal payableAmount = Utils
					.zeroIfNull(
							fullReductionFreeFreight ? BigDecimal.ZERO
									: actualOrderDetail.getFreight())
					.add(actualOrderDetail.getProductPrice()
							.multiply(
									new BigDecimal(actualOrderDetail
											.getProductCount())))
					.add(Utils.zeroIfNull(actualOrderDetail.getDiscount()))
					.add(actualOrderDetail.getTaxFee()
							.multiply(
									new BigDecimal(actualOrderDetail
											.getProductCount())))
					.add(actualOrderDetail.getServiceAmount())
					.subtract(actualOrderDetail.getIntegralDeductionAmount())
					.subtract(
							Utils.zeroIfNull(actualOrderDetail
									.getYmtCouponAmount()))
					.subtract(
							Utils.zeroIfNull(actualOrderDetail
									.getYmtPromotionAmount()))
					.subtract(
							Utils.zeroIfNull(actualOrderDetail
									.getSellerCouponAmount()))
					.subtract(
							Utils.zeroIfNull(actualOrderDetail
									.getPromotionAmount()))
					.subtract(
							Utils.zeroIfNull(actualOrderDetail
									.getRegionDiscountAmount()));
			
			DataUtil.verifyDecimalEquals(payableAmount,
					actualOrderDetail.getPayableAmount(), "验证数据库PayableAmount");
			
			DataUtil.verifyDecimalEquals(expectedOrderDetail.getRegionDiscountValue(),
					actualOrderDetail.getRegionDiscountAmount(), "验证数据库RegionDiscountAmount");
			
			Logger.verifyEquals(expectedOrderDetail.getItemVo()
					.getActivityType(), actualOrderDetail.getActivityType(),
					"验证数据库ActivityType");
			Logger.verifyEquals(
                    expectedOrderDetail.getItemVo().getCdfVipCode(),
					actualOrderDetail.getCdfVipCode(),
					"验证数据库CdfVipCode");

            Logger.verifyEquals(
                    FormatUtil.beanToGSONString(expectedOrderDetail.getItemVo()
                            .getExchangeBuyThresholdProducts()),
                    actualOrderDetail.getExchangeBuyThresholdProducts() == null ? "null"
                            : actualOrderDetail
                            .getExchangeBuyThresholdProducts(),
                    "验证数据库ExchangeBuyThresholdProducts");

			// 校验订单商品扩展表(order_detail_ext)
			verifyOrderDetailExtDb(expectedOrderDetail, actualOrderDetail);

			// 订单商品是 套装商品
			if (expectedOrderDetail.getItemVo().isSubProduct()) {

				// 校验订单组合子商品表（order_detail_sub）
				verifyOrderDetailSubDb(actualOrderDetail, goodsOwnerId);
			}
		}
	}

	/**
	 * 校验营销表（order_detail_promotion）
	 * 
	 * @param expectedOrderItem
	 * @param actualOrderDetailPromotion
	 */
	public void verifyOrderDetailPromotionDb(OrderItem expectedOrderItem,
			OrderDetailPromotionPo actualOrderDetailPromotion, long orderId) {

		Logger.comment(String.format(
				"校验营销表（order_detail_promotion）orderId:%s orderDetailId:%s",
				orderId, actualOrderDetailPromotion.getOrderDetailId()));

		SellerPromotionVo expectedSellerPromotion = expectedOrderItem
				.getSellerPromotion();

		Logger.verifyEquals(
				true,
				Utils.calcTimeSpanMin(actualOrderDetailPromotion.getAddTime()) < 2,
				"验证数据库AddTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualOrderDetailPromotion
						.getUpdateTime()) < 2, "验证数据库UpdateTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(orderId, actualOrderDetailPromotion.getOrderId(),
				"验证数据库OrderId");

		Logger.verifyEquals(expectedOrderItem.getItemVo().getCatalogId(),
				actualOrderDetailPromotion.getCatalogId(), "验证数据库CatalogId");

		DataUtil.verifyDecimalEquals(
				expectedSellerPromotion.getReducedAmount(),
				actualOrderDetailPromotion.getReducedAmount(),
				"验证数据库ReducedAmount");

		Logger.verifyEquals(expectedSellerPromotion.getId(),
				Long.valueOf(actualOrderDetailPromotion.getPromotionId()),
				"验证数据库PromotionId");
		Logger.verifyEquals(expectedSellerPromotion.getType().getCode(),
				actualOrderDetailPromotion.getPromotionType(),
				"验证数据库PromotionType");
		Logger.verifyEquals(expectedSellerPromotion.getName(),
				actualOrderDetailPromotion.getPromotionName(),
				"验证数据库PromotionName");

		Logger.verifyEquals(
				String.valueOf(expectedSellerPromotion.getPromotionValue()),
				actualOrderDetailPromotion.getPromotionValue(),
				"验证数据库PromotionValue");

		String condition = null;

		if (expectedSellerPromotion.getQtyCondition() > 0) {
			condition = "" + expectedSellerPromotion.getQtyCondition();
		} else if (expectedSellerPromotion.getAmountCondition() != null) {
			condition = "" + expectedSellerPromotion.getAmountCondition();
		}

		Logger.verifyEquals(condition,
				actualOrderDetailPromotion.getMatchCondition(),
				"验证数据库MatchCondition");
	}

	/**
	 * 校验订单商品扩展表(order_detail_ext)
	 * 
	 * @param expectedOrderDetail
	 * @param actualOrderDetail
	 */
	private void verifyOrderDetailExtDb(OrderItem expectedOrderDetail,
			OrderDetailPo actualOrderDetail) {

		Long orderDetailId = actualOrderDetail.getOrderDetailId();

		Logger.comment(String.format(
				"校验订单商品表扩展表(order_detail_ext) orderId:%s,OrderDetailId:%s",
				actualOrderDetail.getOrderId(), orderDetailId));

		OrderDetailExtPo actualOrderDetailExt = orderWapper
				.selectOrderDetailExtByOrderId(actualOrderDetail
						.getOrderDetailId());

		Logger.verifyEquals(orderDetailId,
				actualOrderDetailExt.getOrderDetailId(), "验证数据库OrderDetailId");
		Logger.verifyEquals(actualOrderDetail.getCatalogId(),
				actualOrderDetailExt.getCatalogId(), "验证数据库CatalogId");

		Logger.verifyEquals(
				true,
				Utils.calcTimeSpanMin(actualOrderDetailExt.getUpdateTime()) < 2,
				"验证数据库UpdateTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(true,
				Utils.calcTimeSpanMin(actualOrderDetailExt.getAddTime()) < 2,
				"验证数据库AddTime跟系统当前时间差为2分钟内");

		Logger.verifyEquals(actualOrderDetail.getOrderId(),
				actualOrderDetailExt.getOrderId(), "验证数据库OrderId");
		Logger.verifyEquals(expectedOrderDetail.getItemVo().getProperty(),
				actualOrderDetailExt.getPropertyInfo(), "验证数据库PropertyInfo");
		Logger.verifyEquals(expectedOrderDetail.getItemVo().getBrandId(),
				actualOrderDetailExt.getBrandId(), "验证数据库BrandId");
		Logger.verifyEquals(expectedOrderDetail.getItemVo().getPictureUrl(),
				actualOrderDetailExt.getPictureUrl(), "验证数据库PictureUrl");
		Logger.verifyEquals(expectedOrderDetail.getItemVo().getSku(),
				actualOrderDetailExt.getSku(), "验证数据库Sku");
		Logger.verifyEquals(expectedOrderDetail.getItemVo().getProductName(),
				actualOrderDetailExt.getTitle(), "验证数据库Title");
		Logger.verifyEquals(expectedOrderDetail.getItemVo()
				.getProductRecordNo(), actualOrderDetailExt.getRecordNo(),
				"验证数据库RecordNo");
	}

	/**
	 * 校验订单组合子商品表（order_detail_sub）
	 * 
	 * @param actualOrderDetail
	 * @throws Exception
	 */
	private void verifyOrderDetailSubDb(OrderDetailPo actualOrderDetail,
			Long goodsOwnerId) throws Exception {

		long orderDetailId = actualOrderDetail.getOrderDetailId();
		long orderId = actualOrderDetail.getOrderId();

		orderShardingWapper.clearCache();
		
		List<OrderDetailSubPo> actualSubPoList = orderShardingWapper
				.selectOrderDetailSubByDetailId(orderDetailId)
				.stream()
				.sorted(Comparator.comparing(OrderDetailSubPo::getSubCatalogId))
				.collect(Collectors.toList());
		
		String catalogId = actualOrderDetail.getCatalogId();
		
		PackageInfoByCatalogIdListResponse response = SqTradingProductService
				.getPackageInfoByCatalogIdList(goodsOwnerId, Arrays
						.asList(catalogId.startsWith("speecc") ? catalogId
								.substring(6) : catalogId));

		List<SubCatalog> subCataLogs = response.getProductPackageList().get(0)
				.getSubCatalogList().stream()
				.sorted(Comparator.comparing(SubCatalog::getOriginCatalogId))
				.collect(Collectors.toList());

		if (CollectionUtils.isEmpty(actualSubPoList)) {

			String msg = String
					.format("校验订单组合子商品表（order_detail_sub） orderId:%s,catalogId:%s 套装子商品为null",
							actualOrderDetail.getOrderId(), catalogId);
			Logger.comment(msg);

			Logger.fail(new Exception(msg));

			return;
		}

		Logger.verifyEquals(subCataLogs.size(), actualSubPoList.size(),
				"验证子商品个数");

		Logger.comment(String.format(
				"校验订单组合子商品表（order_detail_sub） orderId:%s,catalogId:%s",
				actualOrderDetail.getOrderId(), catalogId));

		BigDecimal fProductPrice = actualOrderDetail.getProductPrice();

		int iAmount = actualOrderDetail.getProductCount();

		// 运费
		BigDecimal fFreight = actualOrderDetail.getFullReductionFreeFreight() ? BigDecimal.ZERO
				: actualOrderDetail.getFreight();

		// 买手优惠券
		BigDecimal fSellerCouponAmount = actualOrderDetail
				.getSellerCouponAmount();

		// 平台优惠券
		BigDecimal fYmtCouponAmount = actualOrderDetail.getYmtCouponAmount();

		// 买手优惠金额
		BigDecimal fSellerPromotionAmount = actualOrderDetail
				.getPromotionAmount();

		// 平台优惠金额
		BigDecimal fymtPromotionAmount = actualOrderDetail
				.getYmtPromotionAmount();

		// 商品税费
		BigDecimal fTaxFee = actualOrderDetail.getTaxFee();

		// 折扣金额
		BigDecimal fDiscount = actualOrderDetail.getDiscount();
		
		// 商品积分
		Long fIntegral = actualOrderDetail.getIntegral();

		// 积分抵扣金额
		BigDecimal fIntegralDeductionAmount = actualOrderDetail.getIntegralDeductionAmount();
		
		// 区域折扣金额
		BigDecimal fRegionDiscountAmount = actualOrderDetail
				.getRegionDiscountAmount();

		// 分摊权重
		BigDecimal[] weight = new BigDecimal[subCataLogs.size()];

		for (int j = 0; j < subCataLogs.size(); j++) {

			SubCatalog subCatalog = subCataLogs.get(j);

			weight[j] = subCatalog.getPrice().multiply(
					new BigDecimal(subCatalog.getNum()));
		}

		BigDecimal price[] = Utils.apportionByWeights(
				fProductPrice.multiply(new BigDecimal(iAmount)), weight);

		BigDecimal freight[] = Utils.apportionByWeights(fFreight, weight);

		BigDecimal sellerCoupon[] = Utils.apportionByWeights(
				fSellerCouponAmount, weight);

		BigDecimal ymtCoupon[] = Utils.apportionByWeights(fYmtCouponAmount,
				weight);

		BigDecimal sellerPromotionAmount[] = Utils.apportionByWeights(
				fSellerPromotionAmount, weight);

		BigDecimal ymtPromotionAmount[] = Utils.apportionByWeights(
				fymtPromotionAmount, weight);

		boolean isNegate = fDiscount.compareTo(
				BigDecimal.ZERO) == -1 ? true : false;

		BigDecimal discount[] = Utils.apportionByWeights(fDiscount.abs(), weight);

		BigDecimal taxFee[] = Utils.apportionByWeights(
				fTaxFee.multiply(new BigDecimal(iAmount)), weight);
		
		BigDecimal integral[] = Utils.apportionByWeightsWithCurrency(
				new BigDecimal(fIntegral), weight, "JPY");
		
		BigDecimal integralDeductionAmount[] = Utils.apportionByWeights(
				fIntegralDeductionAmount, weight);
		
		BigDecimal regionDiscountAmount[] = Utils.apportionByWeights(
				fRegionDiscountAmount, weight);

		int k = 0;

		for (OrderDetailSubPo actualOrderDetailSub : actualSubPoList) {

			Logger.comment(String.format("套装子商品序号 %s",
					actualOrderDetailSub.getId()));

			Logger.verifyEquals(orderId, actualOrderDetailSub.getOrderId(),
					"验证数据库OrderId");

			Logger.verifyEquals(orderDetailId,
					actualOrderDetailSub.getOrderDetailId(),
					"验证数据库OrderDetailId");

			DataUtil.verifyDecimalEquals(freight[k], actualOrderDetailSub.getFreight(),
					"验证数据库Freight");

			Logger.verifyEquals(
					true,
					Utils.calcTimeSpanMin(actualOrderDetailSub.getAddTime()) < 2,
					"验证数据库AddTime跟系统当前时间差为2分钟内");

			Logger.verifyEquals(
					true,
					Utils.calcTimeSpanMin(actualOrderDetailSub.getUpdateTime()) < 2,
					"验证数据库UpdateTime跟系统当前时间差为2分钟内");

			DataUtil.verifyDecimalEquals(sellerPromotionAmount[k],
					actualOrderDetailSub.getPromotionAmount(),
					"验证数据库PromotionAmount");

			DataUtil.verifyDecimalEquals(BigDecimal.ZERO,
					actualOrderDetailSub.getThirdpartyDiscount(),
					"验证数据库ThirdpartyDiscount");

			Logger.verifyEquals(catalogId, actualOrderDetailSub.getCatalogId(),
					"验证数据库CatalogId");

			DataUtil.verifyDecimalEquals(ymtCoupon[k],
					actualOrderDetailSub.getYmtCouponAmount(),
					"验证数据库YmtCouponAmount");

			DataUtil.verifyDecimalEquals(sellerCoupon[k],
					actualOrderDetailSub.getSellerCouponAmount(),
					"验证数据库SellerCouponAmount");

			DataUtil.verifyDecimalEquals(ymtPromotionAmount[k],
					actualOrderDetailSub.getYmtPromotionAmount(),
					"验证数据库ymtPromotionAmount");

			DataUtil.verifyDecimalEquals(isNegate ? discount[k].negate() : discount[k],
					actualOrderDetailSub.getDiscount(), "验证数据库Discount");

			DataUtil.verifyDecimalEquals(price[k],
					actualOrderDetailSub.getProductPrice(), "验证数据库ProductPrice");

			DataUtil.verifyDecimalEquals(taxFee[k],
					actualOrderDetailSub.getTotalTaxFee(), "验证数据库TotalTaxFee");

			Logger.verifyEquals(subCataLogs.get(k).getMainPic(),
					actualOrderDetailSub.getPictureUrl(), "验证数据库PictureUrl");

			Logger.verifyEquals(subCataLogs.get(k).getPropertyValue(),
					actualOrderDetailSub.getPropertyInfo(), "验证数据库PropertyInfo");
			
			if (isCDFMember(goodsOwnerId)) {
				
				Logger.verifyEquals(true,
						actualOrderDetailSub.getIntegral() >= 0, "验证数据库Integral");
				
				if (null == placeOrderReq.getIntegralExchangeRate()) {

					DataUtil.verifyDecimalEquals(new BigDecimal(
							actualOrderDetail.getIntegral()), actualOrderDetail
							.getIntegralDeductionAmount(),
							"验证数据库IntegralDeductionAmount");
				} else {

					DataUtil.verifyDecimalEquals(
							new BigDecimal(actualOrderDetail.getIntegral())
									.multiply(
											placeOrderReq
													.getIntegralExchangeRate())
									.setScale(2, BigDecimal.ROUND_HALF_DOWN),
							actualOrderDetail.getIntegralDeductionAmount(),
							"验证数据库IntegralDeductionAmount");
				}
			} else {
				
				DataUtil.verifyDecimalEquals(integral[k],
						actualOrderDetailSub.getIntegral(), "验证数据库Integral");
				
				DataUtil.verifyDecimalEquals(integralDeductionAmount[k],
						actualOrderDetailSub.getIntegralDeductionAmount(), "验证数据库IntegralDeductionAmount");
			}
			
			DataUtil.verifyDecimalEquals(regionDiscountAmount[k],
					actualOrderDetailSub.getRegionDiscountAmount(), "验证数据库RegionDiscountAmount");
			
			k++;
		}
		
		if (goodsOwnerId == multiCDFCodeGoodsOwnerId) {
			
			int totalCount = actualSubPoList.stream()
					.map(subPo -> subPo.getProductCount()).reduce(Integer::sum)
					.orElse(0);
			
			this.verifyOrderDetailSubCodeDb(actualOrderDetail.getOrderId(),
					actualOrderDetail.getCatalogId(), totalCount
							* actualOrderDetail.getProductCount());
		}
	}
	
	public void verifyOrderDetailSubCodeDb(long orderId, String catalogId,
			Integer expectedCount) {

		List<OrderDetailSubCodePo> orderDetailSubCodePoList = orderShardingWapper
				.selectOrderDetailSubCodebyOrderIdAndCatalogId(orderId,
						catalogId);

		Integer actualCount = orderDetailSubCodePoList.stream()
				.map(detail -> detail.getProductCount()).reduce(Integer::sum)
				.orElse(0);
		Logger.verifyEquals(expectedCount, actualCount,
				String.format("验证该%s使用的子码总数", catalogId));
	}

	/**
	 * 校验神器代理链表（shenqi_proxy_chain）
	 * 
	 * @param expectedShenqiProxyChainPoList
	 * @param orderId
	 * @param catalogId
	 */
	public void verifyShenqiProxyChainDb(
			List<ShenqiProxyChainPo> expectedShenqiProxyChainPoList,
			long orderId, String catalogId) {
		
		orderShardingWapper.clearCache();
		
		List<ShenqiProxyChainPo> actualShenqiProxyChainPoList = orderShardingWapper
				.selectProxyChainbyOrderIdAndCatalogId(orderId, catalogId);

		for (int i = 0; i < expectedShenqiProxyChainPoList.size(); i++) {

			long sellerId = expectedShenqiProxyChainPoList.get(i).getSellerId();

			Logger.comment("校验神器链条表orderId:" + orderId +
					", catalogId:" + actualShenqiProxyChainPoList.get(i).getCatalogId() +
					", index:" + actualShenqiProxyChainPoList.get(i).getIndexInChain());
			Logger.verifyEquals(orderId, actualShenqiProxyChainPoList.get(i)
					.getOrderId(), "验证数据库orderId");
			Logger.verifyEquals(catalogId, actualShenqiProxyChainPoList.get(i)
					.getCatalogId(), "验证数据库catalogId");
			Logger.verifyEquals(expectedShenqiProxyChainPoList.get(i)
					.getTitle(),
					actualShenqiProxyChainPoList.get(i).getTitle(),
					"验证数据库title");
			Logger.verifyEquals(expectedShenqiProxyChainPoList.get(i)
					.getPictureUrl(), actualShenqiProxyChainPoList.get(i)
					.getPictureUrl() == null ? ""
					: actualShenqiProxyChainPoList.get(i).getPictureUrl(),
					"验证数据库PictureUrl");
			Logger.verifyEquals(expectedShenqiProxyChainPoList.get(i)
					.getFromParentPrice(), actualShenqiProxyChainPoList.get(i)
					.getFromParentPrice(), "验证数据库FromParentPrice");
			Logger.verifyEquals(expectedShenqiProxyChainPoList.get(i)
					.getToChildPrice(), actualShenqiProxyChainPoList.get(i)
					.getToChildPrice(), "验证数据库ToChildPrice");
			Logger.verifyEquals(expectedShenqiProxyChainPoList.get(i)
					.getIndexInChain(), actualShenqiProxyChainPoList.get(i)
					.getIndexInChain(), "验证数据库IndexInChain");
			Logger.verifyEquals(sellerId, actualShenqiProxyChainPoList.get(i)
					.getSellerId(), "验证数据库SellerId");
			Logger.verifyEquals(true, Utils
					.calcTimeSpanMin(actualShenqiProxyChainPoList.get(i)
							.getAddTime()) < 2, "验证数据库AddTime跟系统当前时间差为2分钟内");
			Logger.verifyEquals(true, Utils
					.calcTimeSpanMin(actualShenqiProxyChainPoList.get(i)
							.getUpdateTime()) < 2,
					"验证数据库UpdateTime跟系统当前时间差为2分钟内");

			if (expectedShenqiProxyChainPoList.size() == (i + 1))
				Logger.verifyEquals(0L, actualShenqiProxyChainPoList.get(i)
						.getChildSellerId(), "验证数据库ChildSellerId");
			else
				Logger.verifyEquals(expectedShenqiProxyChainPoList.get(i + 1)
						.getSellerId(), actualShenqiProxyChainPoList.get(i)
						.getChildSellerId(), "验证数据库ChildSellerId");

			Logger.verifyEquals(expectedShenqiProxyChainPoList.get(i)
					.getProxyCatalogId(), actualShenqiProxyChainPoList.get(i)
					.getProxyCatalogId(), "验证数据库ProxyCatalogId");

			Logger.verifyEquals(expectedShenqiProxyChainPoList.get(i)
					.getFromParentPriceType(), actualShenqiProxyChainPoList
					.get(i).getFromParentPriceType(),
					"验证数据库FromParentPriceType");
			Logger.verifyEquals(Utils
					.falseIfNull(expectedShenqiProxyChainPoList.get(i)
							.getIsFenxiaoShop()), actualShenqiProxyChainPoList
					.get(i).getIsFenxiaoShop(), "验证数据库IsFenxiaoShop");

			DataUtil.verifyDecimalEquals(expectedShenqiProxyChainPoList.get(i)
					.getSalePrice(), actualShenqiProxyChainPoList.get(i)
					.getSalePrice(), "验证数据库SalePrice");
		}
	}

	public void verifyShenqiSellerProfit(OrderPo orderPo,
			List<OrderDetailPo> orderDetailList, boolean isInherited, List<ShenqiProxyChainPo> shenqiProxyChain) {

		long orderId = orderPo.getOrderId();
		BigDecimal payableAmount = orderPo.getPayableAmount();

		if (orderPo.getSellerId() == orderPo.getGoodsOwnerId()) {

			ShenqiSellerProfitPo expectShenqiSellerProfitPo = new ShenqiSellerProfitPo();

			expectShenqiSellerProfitPo.setOrderId(orderId);
			expectShenqiSellerProfitPo.setSellerId(orderPo.getSellerId());
			expectShenqiSellerProfitPo.setSellerRole(3);
			expectShenqiSellerProfitPo.setProfit(payableAmount.subtract(Utils
					.zeroIfNull(orderPo.getServiceAmount())));
			expectShenqiSellerProfitPo.setChildSellerId(0L);

			this.verifyShenqiSellerProfitDb(expectShenqiSellerProfitPo,
					orderId, orderPo.getSellerId());
		} else {

			// 客服的收入
			BigDecimal serviceIncome = BigDecimal.ZERO;

			BigDecimal taxFee = orderDetailList
					.stream()
					.map(p -> p.getTaxFee().multiply(
							new BigDecimal(p.getProductCount())))
					.reduce(BigDecimal.ZERO, BigDecimal::add);

			// 代理订单的运费不从订单上取，订单上的运费会被fullReductionFreeFreight影响
			BigDecimal freight = orderDetailList.stream()
					.map(p -> p.getFreight())
					.reduce(BigDecimal.ZERO, BigDecimal::add);

			int i = 1;
			
			// 店主的总收入
			BigDecimal shopOwnerTotalProfit = BigDecimal.ZERO;
			// 货头的总收入
			BigDecimal goodsOwnerTotalProfit = BigDecimal.ZERO;
			// 中间商的总收入
			BigDecimal middlerManTotalProfit = BigDecimal.ZERO;
			
			for (ShenqiProxyChainPo chainPo : shenqiProxyChain) {

				ShenqiSellerProfitPo expectShenqiSellerProfitPo = new ShenqiSellerProfitPo();

				if (chainPo.getIndexInChain() == 0
						&& orderPo.getSellerId() != orderPo.getGoodsOwnerId()) {

					// 货头的总收入
					goodsOwnerTotalProfit = CalculateShenqiSellerProfit
							.calProductTotalProfit(orderDetailList,
									isInherited, chainPo, shenqiProxyChain,
									orderPo, i, taxFee, freight,
									SqSellerRoleEnum.GoodOwner.getCode(), null);

					expectShenqiSellerProfitPo.setSellerRole(2);
				} else if (chainPo.getSellerId().longValue() == orderPo
						.getSellerId().longValue()) {

					// 店主的总收入
					shopOwnerTotalProfit = CalculateShenqiSellerProfit
							.calProductTotalProfit(orderDetailList,
									isInherited, chainPo, shenqiProxyChain,
									orderPo, i, taxFee, freight,
									SqSellerRoleEnum.ShopOwner.getCode(), null);

					expectShenqiSellerProfitPo.setSellerRole(1);
				} else {

					// 中间商的总收入
					middlerManTotalProfit = CalculateShenqiSellerProfit
							.calProductTotalProfit(orderDetailList,
									isInherited, chainPo, shenqiProxyChain,
									orderPo, i, taxFee, freight,
									SqSellerRoleEnum.MiddlerMan.getCode(), null);

					expectShenqiSellerProfitPo.setSellerRole(4);
				}

				if (isInherited) {
					
					// 如果是继承代理，需要提前知道店主的利润
					shopOwnerTotalProfit = CalculateShenqiSellerProfit
							.calProductTotalProfit(orderDetailList,
									isInherited, chainPo, shenqiProxyChain,
									orderPo, i, taxFee, freight,
									SqSellerRoleEnum.ShopOwner.getCode(),
									null);

					if (shenqiProxyChain.size() >= 3) {

						goodsOwnerTotalProfit = goodsOwnerTotalProfit.add(
								taxFee).add(freight);

						if (shenqiProxyChain.size() - 1 == i) {

							// 优惠总额：买手优惠券 + 买手满减优惠
							BigDecimal totalPromotion = orderPo
									.getPromotionAmount()
									.add(orderPo.getSellerCouponAmount());

							middlerManTotalProfit = middlerManTotalProfit
									.add(orderPo.getOrderDiscount())
									.subtract(freight)
									.add(orderPo.getFreight())
									.subtract(shopOwnerTotalProfit)
									.subtract(totalPromotion);
							expectShenqiSellerProfitPo
									.setSubDistributionProfit(shopOwnerTotalProfit
											.setScale(2,
													BigDecimal.ROUND_DOWN));
						}
					} else {

						goodsOwnerTotalProfit = orderPo.getPayableAmount()
								.subtract(shopOwnerTotalProfit);

						if (shenqiProxyChain.size() - 1 == i)
							expectShenqiSellerProfitPo
									.setSubDistributionProfit(shopOwnerTotalProfit);
					}
				} else {

					// 优惠总额：买手优惠券 + 买手满减优惠
					BigDecimal totalPromotion = orderPo
							.getPromotionAmount().add(
									orderPo.getSellerCouponAmount());

					shopOwnerTotalProfit = shopOwnerTotalProfit
							.add(orderPo.getOrderDiscount())
							.subtract(totalPromotion).subtract(freight)
							.add(orderPo.getFreight())
							.subtract(orderPo.getRegionDiscountAmount());
					goodsOwnerTotalProfit = goodsOwnerTotalProfit.add(
							freight).add(taxFee);
				}

				expectShenqiSellerProfitPo.setOrderId(orderId);
				expectShenqiSellerProfitPo.setSellerId(chainPo
						.getSellerId());
				expectShenqiSellerProfitPo.setChildSellerId(chainPo
						.getChildSellerId());

				// 如果是货头
				if (chainPo.getIndexInChain() == 0
						&& orderPo.getSellerId() != orderPo
								.getGoodsOwnerId()) {

					expectShenqiSellerProfitPo
							.setProfit(goodsOwnerTotalProfit);
				}
				// 如果是店主
				else if (chainPo.getSellerId().longValue() == orderPo
						.getSellerId().longValue()) {

					expectShenqiSellerProfitPo
							.setProfit(shopOwnerTotalProfit);
				}
				// 如果是中间商
				else {

					expectShenqiSellerProfitPo
							.setProfit(middlerManTotalProfit);
				}

				serviceIncome = expectShenqiSellerProfitPo.getProfit();

				this.verifyShenqiSellerProfitDb(expectShenqiSellerProfitPo,
						orderId, expectShenqiSellerProfitPo.getSellerId());

				i = i + 1;
			}

			if (orderPo.getSalesman() != 0) {

				ShenqiSellerProfitPo expectShenqiSellerProfitPo = new ShenqiSellerProfitPo();

				expectShenqiSellerProfitPo.setOrderId(orderId);
				expectShenqiSellerProfitPo.setSellerId(orderPo
						.getSalesman());
				expectShenqiSellerProfitPo.setSellerRole(5);
				expectShenqiSellerProfitPo.setProfit(serviceIncome);
				expectShenqiSellerProfitPo.setChildSellerId(0L);

				this.verifyShenqiSellerProfitDb(expectShenqiSellerProfitPo,
						orderId, orderPo.getSalesman());
			}
		}
	}
	
	/**
	 * 校验神器卖家利润表（shenqi_seller_profit）
	 * 
	 * @param expectShenqiSellerProfitPo
	 * @param orderId
	 * @param sellerId
	 */
	private void verifyShenqiSellerProfitDb(
			ShenqiSellerProfitPo expectShenqiSellerProfitPo, long orderId,
			long sellerId) {

		orderShardingWapper.clearCache();

		Logger.comment(String.format("开始验证sellerId：%s，在orderId：%s 上获得的利润",
				sellerId, orderId));

		ShenqiSellerProfitPo actualShenqiSellerProfitPo = orderShardingWapper
				.selectSellerProfitbyOrderIdAndSellerId(orderId, sellerId);

		Logger.verifyEquals(expectShenqiSellerProfitPo.getOrderId(),
				actualShenqiSellerProfitPo.getOrderId(), "验证orderId");
		Logger.verifyEquals(expectShenqiSellerProfitPo.getSellerId(),
				actualShenqiSellerProfitPo.getSellerId(), "验证sellerId");
		DataUtil.verifyDecimalEquals(expectShenqiSellerProfitPo.getProfit(),
				actualShenqiSellerProfitPo.getProfit(), "验证profit");
		Logger.verifyEquals(expectShenqiSellerProfitPo.getSellerRole(),
				actualShenqiSellerProfitPo.getSellerRole(), "验证sellerRole");
		Logger.verifyEquals(expectShenqiSellerProfitPo.getChildSellerId(),
				actualShenqiSellerProfitPo.getChildSellerId(),
				"验证childSellerId");
		DataUtil.verifyDecimalEquals(
				expectShenqiSellerProfitPo.getSubDistributionProfit(),
				actualShenqiSellerProfitPo.getSubDistributionProfit(),
				"验证subDistributionProfit");
	}

	public void verifyOrderTraveler(List<TravelerVo> travelerVos, Long orderId,
			Long userId, Long sellerId) {

		orderShardingWapper.clearCache();

		Logger.comment("开始验证order_traveler");

		List<OrderTravelerPo> actualOrderTravelerList = orderShardingWapper
				.selectOrderTravelersbyOrderId(orderId);

		// 数据库的出行人顺序和下单时候的顺序一致
		for (int i = 0; i < travelerVos.size(); i++) {

			TravelerVo expectTravelerVo = travelerVos.get(i);
			OrderTravelerPo actualTravelerVo = actualOrderTravelerList.get(i);

			int index = i + 1;

			Logger.comment(String.format("在orderId：%s 第  %s 个旅行者名称：%s",
					orderId, index, expectTravelerVo.getTravelerName()));

			Logger.verifyEquals(orderId, actualTravelerVo.getOrderId(),
					"验证OrderId");
			Logger.verifyEquals(userId, actualTravelerVo.getUserId(),
					"验证UserId");
			Logger.verifyEquals(sellerId, actualTravelerVo.getSellerId(),
					"验证SellerId");
			Logger.verifyEquals(expectTravelerVo.getTravelerName(),
					actualTravelerVo.getTravelerName(), "验证TravelerName");
			Logger.verifyEquals(expectTravelerVo.getTravelerPhone(),
					actualTravelerVo.getTravelerPhone(), "验证TravelerPhone");
			Logger.verifyEquals(index, actualTravelerVo.getTravelerIndex(),
					"验证TravelerIndex");
			DataUtil.verifyDateEquals(expectTravelerVo.getTravelerDate(),
					actualTravelerVo.getTravelerDate(), "验证TravelerDate");
			Logger.verifyEquals(expectTravelerVo.getTravelerIdcard(),
					actualTravelerVo.getTravelerIdCard(), "验证TravelerIdCard");
			Logger.verifyEquals(expectTravelerVo.getRemark(),
					actualTravelerVo.getRemark(), "验证Remark");

			Logger.verifyEquals(true,
					Utils.calcTimeSpanMin(actualTravelerVo.getAddTime()) < 2,
					"验证数据库AddTime跟系统当前时间差为2分钟内");
			Logger.verifyEquals(
					true,
					Utils.calcTimeSpanMin(actualTravelerVo.getUpdateTime()) < 2,
					"验证数据库UpdateTime跟系统当前时间差为2分钟内");
		}
	}
	
	public void verifyOrderCouponDetail(
			List<OrderCouponDetailPo> orderCouponDetailList, Long orderId,
			Long mainOrderId) {

		orderShardingWapper.clearCache();

		Logger.comment("开始验证order_coupon_detail");

		List<OrderCouponDetailPo> actualOrderCouponDetailList = orderShardingWapper
				.selectOrderCouponDetailbyOrderId(orderId);
		
		actualOrderCouponDetailList.size();
		orderCouponDetailList.size();
		
		for (int i = 0; i < orderCouponDetailList.size(); i++) {

			OrderCouponDetailPo expectOrderCouponDetailVo = orderCouponDetailList.get(i);
			OrderCouponDetailPo actualOrderCouponDetailVo = actualOrderCouponDetailList.get(i);
			
			Logger.comment(String.format("在orderId：%s 第  %s 个优惠券码：%s", orderId,
					i + 1, expectOrderCouponDetailVo.getCouponCode()));

			Logger.verifyEquals(mainOrderId,
					actualOrderCouponDetailVo.getMainOrderId(), "验证MainOrderId");
			Logger.verifyEquals(expectOrderCouponDetailVo.getCouponCode(),
					actualOrderCouponDetailVo.getCouponCode(), "验证CouponCode");
			Logger.verifyEquals(expectOrderCouponDetailVo.getCouponType(),
					actualOrderCouponDetailVo.getCouponType(), "验证CouponType");
			Logger.verifyEquals(expectOrderCouponDetailVo.getCouponSource(),
					actualOrderCouponDetailVo.getCouponSource(),
					"验证CouponSource");
			DataUtil.verifyDecimalEquals(expectOrderCouponDetailVo.getAmount(),
					actualOrderCouponDetailVo.getAmount(), "验证Amount");
			Logger.verifyEquals(expectOrderCouponDetailVo.getDeleted(),
					actualOrderCouponDetailVo.getDeleted(), "验证Deleted");

			Logger.verifyEquals(true,
					Utils.calcTimeSpanMin(actualOrderCouponDetailVo
							.getAddTime()) < 2, "验证数据库AddTime跟系统当前时间差为2分钟内");
			Logger.verifyEquals(true,
					Utils.calcTimeSpanMin(actualOrderCouponDetailVo
							.getUpdateTime()) < 2,
					"验证数据库UpdateTime跟系统当前时间差为2分钟内");
		}
	}
	
	public static void main(String[] args) {
		
		System.out.println(Integer.toBinaryString(0));
		
		DGSQPlaceOrderVerifyService test = new DGSQPlaceOrderVerifyService(null, null);

		OrderPo orderPo = test.orderShardingWapper
				.selectOrderbyOrderId(14323508699L);
		List<OrderDetailPo> orderDetailList = test.orderShardingWapper
				.selectOrderDetailbyOrderId(14323508699L);

		List<ShenqiProxyChainPo> shenqiProxyChain = SqTradingProductService
				.getInheritedProxyChainInfo(
						"c9547326",
						orderPo.getSellerId());

		test.verifyShenqiSellerProfit(orderPo, orderDetailList, true, shenqiProxyChain);
//
//		System.out
//				.println(Utils
//						.decryptAES("047A6F9D2C325EF917D06C5E7C2CE88A99C5E3164CF5FD439E28699583E914633C74C4B1D72AC0CD0A26AE277C614B1608BF8F90E00C3A38F1EF9D2EC9751ACB2BCE0F4B24164B78806B805AA9442780720B606572D3C82F86AE953DA8EB1315"));
	}
}
